てくてく

小説をサイトに載せるとき気付いたんです。
「中身ほとんど一緒なんだからぱっと置き換えたら楽なんじゃない?」
最近PHPでパーツの共通化してとても便利ではあったのですが、小説本文をペッと貼ったらパッとhtml形式で書き出してくれたら楽できるなって気付いたんです。
ということでそんな小説をhtmlに書き出してくれる置き換えスクリプトを作りました!
今回は配布ありです。

配布
ダウンロードはこちら⇨novel 2 template
免責事項をご確認の上、ご利用くださいませ。

デモはこちらより確認できます。

内容物
  • index.html
  • readme.txt
  • script.js
  • style.css


確認環境はGoogle Chromeのみです。またローカルでの使用を想定しております。

使い方
あらかじめ、以下のものを用意してください。
  • 小説本文
  • 小説を載せたいテンプレート(html、phpどちらでも可)以降テンプレート表記


novel 2 template
index.htmlを開く(ダブルクリック)と規定ブラウザでページが開きます。
各項目を設定します。

◯タイトルタグ
<title>に書きたい内容。
置き換えの必要がない場合は空欄で大丈夫です。

◯cssのURL
ファイルを配置する場所からcssまでのパス。
文字を置き換えるだけなので、相対パス・絶対パスどちらでもOKです。
置き換えの必要がない場合は空欄で大丈夫です。

◯作品タイトル
小説のタイトル。
置き換えの必要がない場合は空欄で大丈夫です。

◯本文
小説本文。通常だとタグに囲まれずそのまま置き換えられます。
置き換えの必要がない場合は空欄で大丈夫です。
下記の機能があります。
・改行タグを入れる
 - 改行済みテキストの場合、改行タグを挿入します。デフォルトでチェックが入っています。
・空行が◯行以上ならpタグで囲む
 - 空行の行数を指定すると、その間のテキストをpタグで囲みます。
・ルビ表記をルビタグに差し替える
 - 特定のルビ表記をルビタグに変更します。対応しているルビ表記は後述です。
・pタグとpタグの間に水平タグを挟む
 - pタグとpタグの間に水平タグを入れます。これは管理人が欲しくて追加したオマケ機能です。

対応しているルビ表記は以下のとおりです。
| 漢字 《かんじ》
#漢字__かんじ__#
[RB:漢字,かんじ]
[[rb: 漢字 > かんじ ]]
[漢字"かんじ"]

◯JavaScriptのURL
JavaScriptのファイルまでのパス。
cssのURL同様、ファイルを配置する場所からJavaScriptファイルまでのパスをいれてください。
置き換えの必要がない場合は空欄で大丈夫です。

◯項目追加
項目名を入れ追加ボタンを押すと、項目を追加できます。
項目名はわかりやすくするためのものなので、未定義のままでも動きます。
追加した項目は削除可能です。追加・削除した項目はナンバリングが再設定されます。

◯ファイルから読み込み
テンプレートファイルがあればこちらから読み込むのが早いです。
読み込むとテンプレート欄に内容が表示されます。

◯テンプレート
ファイルから読み込まない場合、テンプレート欄にテンプレートを記入してください。

◯置き換え
設定した項目をテンプレートに反映させます。
テンプレート欄になにもないとアラートが表示されます。

◯置き換え結果
置き換えた内容をこのエリアに表示します。
内容をコピーしてご利用ください。
整形されていないので、整形したい場合は外部ツールやソフトをご利用くださいませ。

◯ダウンロード
ファイル名(デフォルトはoutput)を記入しhtmlかphpかを選びダウンロードボタンを押すと、置き換え結果の内容を選択した拡張子でダウンロードできます。
なお、サーバーに送信はされませんのでご安心ください。
置き換え結果欄になにもないと、アラートが表示されます。

テンプレートファイルの書き方
novel 2 templateの各項目には[item数字]が書かれています。
この[item数字]を書いた場所が、設定した内容と置き換わる仕組みです。
例1:
タイトルタグフォーム:小説をhtmlに置き換えるスクリプト作ってみたっ
テンプレート:<title>[item0]</title>
書き出されるもの:<title>小説をhtmlに置き換えるスクリプト作ってみたっ</title>

例2:
cssのURLフォーム:../css/style.css
テンプレート:<link rel="stylesheet" href="[item1]" type="text/css" id="style">
書き出されるもの:<link rel="stylesheet" href="../css/style.css" type="text/css" id="style">

例3:
追加した項目[item5]:明日は明日の風が吹く
テンプレート:<p>[item5]</p>
書き出されるもの:<p>明日は明日の風が吹く</p>

カスタマイズ
MITライセンスで配布しておりますので、ご自身のテンプレートに合うように好きに改変していただいて構いません!
カスタマイズ向けの説明は同梱のreadme.txtに記載されています。

最後に
自分用に試しに作ってみたものですが、割といい感じにできたと思います。
カスタマイズ次第では項目追加も不要になると思いますので、自分だけの変換ツールを作ってみてください!

関連記事
簡易ログイン作ってみた!
【JavaScript】名前変換機能を作ってみた!
今は便利な名前変換機能(単語変換機能)スクリプトを配布してくださっている方がいらっしゃいます。
私が自分のサイトに実装した当時、求めている機能が微妙になかったため「作るっきゃねえ!」の精神で自作しました。

デモ
こちらのデモページから動作確認ができます。

仕様
①名字・名前・名字ひらがな・名前ひらがなを変換
②名字と名前はユニークなものを前提としている
③ひらがなは[RB:吃 > ども]りなどで利用
④小説ページごとにデフォルト名が異なっていても対応可能
⑤Cookieを利用
⑥変換フォームのプレースホルダーには変換した名前を入れておく。

ユニークなものとは、重複しない独特なものを意味しています。本文で使われない単語のことです。
例えば、名前が「空」だと「青空の下に広がる海。」など本文に「空」の文字が入っていると仕様上その文字も変換されてしまいます。

基本私が小説を書くときは名前変換を前提としておらず、名前を決めて執筆しています。
htmlに持っていくときに名前の部分にタグ付けがいちいち面倒だな……と思い、JavaScriptの文字列変換を利用して書き換える方向にしました。
ただひらがなはなかなか難しかったため、ひらがなだけタグをつけています。
(私の小説ではそこまで多用しなかったので妥協しました)

ファイル構成
index.html
contents.html
css/style.css
js.name-change.js
今回はjQueryを使いません。
Cookie処理はかわりにjs-cookieを利用しました。

JavaScriptの読み込み
名前変換のフォームがあるページと、名前変換処理をするページで読み込みます。
<!-- js-cookie -->
<script src="https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js"></script>
<!-- script -->
<script src="js/name-change.js"></script>

js-cookieのCDNはこちらからコピペしています。
Cookie操作をしやすいように利用しています。

名前変換フォーム
今回index.htmlに書いてる名前変換のフォームです。
なお、デザインに関するクラスは省いています。
<form name="d_name">
    <input type="text" placeholder="名字" name="lastname">
    <input type="text" placeholder="名前" name="firstname"><br>
    <input type="text" placeholder="みょうじ" name="lastname_hira">
    <input type="text" placeholder="なまえ" name="firstname_hira"><br>
    <button type="button" onclick="setName()">変換</button>
    <button type="button" onclick="resetName()">リセット</button>
</form>
<div id="setName"></div>

onclickの処理はjs/name-change.jsファイルに記述します。
<div id="setName"></div>は変換ボタンやリセットボタンを押した後の結果を表示するためのものです。

style.css
上記<div id="setName"></div>の設定です。
#setName {
    display: none;
    /* 下記はデザイン用 */
    margin: 15px 0;
    padding: 15px;
    border: 1px solid transparent;
    border-radius: 3px;
    margin: 0 0 10px;
    padding: 8px;
}

#setName.change,#setName.reset {
    display: block;
}

#setName.change::after {
    content: "名前を変換しました。";
}

#setName.reset::after {
    content: "名前をリセットしました。";
}

/* 下記はデザイン用 */
#setName.change,#setName.reset {
    border-color: #9ad4de;
    background-color: rgba(154, 212, 222, 0.25);
}


名前変換ありの本文
記述はこのようにします。
<div id="d-name-default"  data-last="デフォルト名字" data-first="デフォルト名前" data-last-hira="でふぉるとみょうじ" data-first-hira="でふぉるとなまえ"></div>
<div id="d-name-nvl">
    <!-- 本文 -- >
</div>

一つずつ解説していきます。

<div id="d-name-default" data-last="デフォルト名字" data-first="デフォルト名前" data-last-hira="でふぉるとみょうじ" data-first-hira="でふぉるとなまえ"></div>
タグはdivにしていますがなんでもいいです。こちらは
<script src="js/name-change.js"></script>
より上に記述してあればどこに記述しても構いません。今回は本文の前に記述しています。
id="d-name-default"でJavaScriptから取得できるようにします。
data-last=""はデフォルトの名字を入れます。省略可能です。
data-first=""はデフォルトの名前を入れます。省略可能です。
data-last-hira=""はデフォルトの名字のひらがな(読み方)を入れます。省略可能です。
data-first-hira=""はデフォルトの名前のひらがな(読み方)を入れます。省略可能です。
この省略可能は、本文で使用しない場合に記述しなくていいようにするものです。

id="d-name-nvl"の中に小説本文を流し込みます。これは上記で設定したデフォルト名と変換フォームで設定した名前を置き換えるためのものです。このidがないと変換されないので注意です。

ひらがなのタグ
名字や名前のひらがな部分にはタグを追加します。
デモ版の場合はこのようにしてます。
「俺は<em>愛上陵</em>!”<em><span class="last-hira">あいうえ</span></em><em><span class="first-hira">おか</span></em>”って読むんだぜ!珍しいだろ?」<br>
 ──<em><span class="last-hira">あ……いう……</span></em>──<br>
「ん?いまなにか聞こえたか?」<br>
 ──<em><span class="last-hira">あい……うえ……</span></em><em><span class="first-hira">お……か</span></em>──<br>
「やっぱ誰かに呼ばれてる!」

名字のひらがなを
<span class="last-hira"></span>
名前のひらがなを
<span class="first-hira"></span>
で囲みます。
このとき間に三点リーダ(…)や句読点が入っても大丈夫です。
もしひらがなの部分に別のタグ(強調タグやルビタグなど)を使いたい場合は、spanタグの外側に設置します。

name-change.js
処理はこちらです。
/* 名前設定 */
function setName() {
    const formEl = document.forms.d_name;
    let change = false;
    change = setItem(formEl.lastname,'lastname');
    change = setItem(formEl.firstname,'firstname');
    change = setItem(formEl.lastname_hira,'lastname_hira');
    change = setItem(formEl.firstname_hira,'firstname_hira');
    if (!change) { return; }
    document.getElementById("setName").classList.remove("reset");
    document.getElementById("setName").classList.add("change");
    /* 同じページ内に変換箇所がある場合 */
    changeName();
}

/* 項目別 */
function setItem(elName,cookieId){
    const name = elName ? elName.value : '';
    if(name === null || name === '') return false;
    Cookies.set(cookieId, name);
    return true;
}

/* 名前変換時にテキストエリアを変換した名前に保持 */
function keepName() {
    const formEl = document.forms.d_name;
    if (!formEl) { return; }
    keepItem(formEl.lastname,'lastname');
    keepItem(formEl.firstname,'firstname');
    keepItem(formEl.lastname_hira,'lastname_hira');
    keepItem(formEl.firstname_hira,'firstname_hira');
    document.getElementById("setName").classList.remove("reset");
    document.getElementById("setName").classList.remove("change");
}

/* 項目別 */
function keepItem(elName,cookieId){
    let input = elName ?? null;
    if(input === null) return;
    const name = Cookies.get(cookieId) ?? input.placeholder;
    if(input.placeholder !== name){
        input.value = name;
    }
}

/* 名前リセット */
function resetName() {
    const formEl = document.forms.d_name;
    let reset = resetItem(formEl.lastname,'lastname');
    reset = resetItem(formEl.firstname,'firstname');
    reset = resetItem(formEl.lastname_hira,'lastname_hira');
    reset = resetItem(formEl.firstname_hira,'firstname_hira');
    if(reset){
        ajaxReload(); // 同一ページに変換箇所がある場合
        document.getElementById("setName").classList.remove("change");
        document.getElementById("setName").classList.add("reset");
    }
}

/* 項目別 */
function resetItem(elName,coolieId){
    Cookies.remove(coolieId);
    if (!elName) return false;
    else elName.value = '';
    return true;
}

/* 名前変換 */
function changeName() {
    let d_name_nvl = document.getElementById('d-name-nvl');
    if (d_name_nvl === null) { return; }
    let str = changeItem('lastname', 'data-last', d_name_nvl.innerHTML);
    str = changeItem('firstname', 'data-first', str);
    d_name_nvl.innerHTML = str;
    changeHiragana('lastname_hira', 'data-last-hira', 'last-hira');
    changeHiragana('firstname_hira', 'data-first-hira', 'first-hira');
}

/* 項目別 */
function changeItem(cookieId,attrName,str){
    const data_d = document.getElementById('d-name-default').getAttribute(attrName);
    const name = Cookies.get(cookieId);
    if(name && data_d) return str.replace(new RegExp(data_d,'g'),name);
    return str;
}

/* ひらがな対応 */
function changeHiragana(cookieId,attrName,className){
    const data_d = document.getElementById('d-name-default').getAttribute(attrName);
    const name = Cookies.get(cookieId);
    if(!(name && data_d)) return;
    let arr = document.getElementsByClassName(className);
    for(i = 0;i<arr.length;i++){
        let el = arr[i];

        let defHira = data_d.split('');
        let nameHira = name.split('');
        let str = el.innerText.split('');
        let txt ='';
        let nameCount = 0;
        for (k = 0; k < str.length; k++) {
            if(!str[k].match(/^[ぁ-んー ]+$/) || defHira.length <= nameCount){
                txt += str[k];
            }else{
                let replace;
                if(nameCount < nameHira.length){
                    replace = nameHira[nameCount];
                    txt += str[k].replace(defHira[nameCount], replace);
                    nameCount++;
                }else if(nameHira.length < defHira.length){
                    // 設定された名前のほうが短ければ以降はつけない
                    break;
                }
            }
        }
       
        // 不足分追加
        if(defHira.length < nameHira.length){
            let substr = name.substr(nameCount);
            txt += substr;
        }

        el.innerText = txt;
    }
}

/* 同じページに変換がある場合 */
function ajaxReload(){
    let d_name_nvl = document.getElementById('d-name-nvl');
    if (d_name_nvl) {
        let url = location.href + "?date="+new Date().getTime();
        let ajax = new XMLHttpRequest;
        ajax.open("GET",url,true);
        ajax.onload = function(){
            var res = ajax.responseText;
            var parse = new DOMParser().parseFromString(res,"text/html");
            d_name_nvl.innerHTML = parse.getElementById('d-name-nvl').innerHTML;
        };
        ajax.send(null);
    }
}

/* 読み込み直後 */
window.onload = function () {
    /* 入力フォームの設定 */
    keepName();
    /* 名前変換 */
    changeName();
};

同一ページに変換箇所がある場合の処理も追記しておきました。
もしない場合はその部分は削除して大丈夫です。
名前を変換する場合は文字を置き換え、リセットする場合は名前変換のあるタグ(d_name_nvl)の中だけをajaxをつかってリロードしています。
一部のみリロードについてはjavascriptでページを一部だけ更新する方法を参考にしました。
ajaxでもどってくる内容はテキストデータなので、htmlにパースして利用しています。テキストのパースは【JavaScript】DOMParserで文字列をHTMLElement・Nodeに変換するを参考にしました。

最後に
実装したのは割と前で記事にしようとしてなかなかできていなかったので、ようやく記事にできて嬉しいです。
「もっと汎用性がほしい!」「もっと使いやすい方がいい!」「全ページ同じにしたい!」と言った場合は、すでに配布されている素晴らしいスクリプトがありますのでそちらを使っていただくといいかもしれないです。
私の場合「名前にいちいちタグしたくない」「デフォルト名が小説によって違う」と自分で用意したほうが良さそうだったので用意してみました。
同じように自作しようとしている方の参考になれば幸いですっ

それと記事に関係ないですが、Twitter(現X)アカウントを作成しました!
Twitter(現X)アカウント てくてく@個人サイト向け情報共有サイト
よければフォローして下さいませ♪

参考
js-cookie
CDN js-cookie
javascriptでページを一部だけ更新する方法
JavaScript】DOMParserで文字列をHTMLElement・Nodeに変換する
DOMParser の parseFromString() メソッドの使い方
個人サイトに連載系の小説を載せるとき、前ページや次ページのリンクをフッターに貼るのですが毎回毎回設定するの、ちょっと面倒になってきちゃったんですよね。
PHPのパーツ共通化利用してなんかいい感じにできないかな~と模索して、無事実装できたのでご紹介します。
なお、高速化などは考えておりませんのであしからず!
【2023/09/26追記】一部プログラムに不足があったので修正しました。

この記事で最終的にできるコト
前ページ/次ページのリンクを自動設定。

今回の確認環境
  • Windows10
  • Google Chrome
  • XAMPP v3.3.0(PHP8.2)
  • ロリポップサーバー(PHP8.2LiteSpeed版)

※XAMPP使用の場合、VirtualHost利用を前提として執筆しています。
VirtualHostは前記事(ローカルでもドメイン使用!?XAMPPのVirtualHostとはっ)を参照くださいませ。

今回のディレクトリ構成
サイトフォルダ
├novels
|├001.php
|├002.php
|├003.php
|└004.php
├parts
|├foot.php
|└head.php
└index.php

上記の中で前ページ/次ページを入れるのはnovelsフォルダ内のみです。
しかしフォルダによってfooterの中身を変えるのすら面倒なので、すべて同じfooterを使います。
処理の都合上、novelsフォルダ内は桁を揃えて連番にしてあります。

各ページ
今回パーツの共通化を前提としています。
よって各ページは下記のようにしております。

head.php
<!DOCTYPE html>
<html>
<head>
    <!-- 省略(headタグの中身) -->
</head>
<body>
    <header>
        <!-- 省略(headerタグの中身) -->
    </header>


foot.php
<!-- ここに処理を書きます。 -->
<footer>
    <nav>
        <ul>
            <!-- 前/次のリンク差し込み -->
            <li><a href="#">pagetop</a></li>
        </ul>
    </nav>
</footer>
</body>
</html>

※最低限のみ載せたのでscript読み込みなど色々省いています。

共通化したパーツを読み込む各ページ
index.phpや001.phpなどです。
<?php include_once($_SERVER['DOCUMENT_ROOT']."/parts/head.php"); ?>
<!-- 省略(bodyタグでheaderより下、footerより上の中身) -->
<?php include_once($_SERVER['DOCUMENT_ROOT']."/parts/foot.php"); ?>



追記する処理と解説
foot.phpに追記していきます。
<!-- ▼▼ここから追記▼▼ -->
<?php
if(basename(getcwd()) === "novels"){
    $array = glob("*");
    $current = pathinfo($_SERVER['REQUEST_URI'], PATHINFO_BASENAME);
    $is_prev = false;
    for($i = 0 ; $i < count($array) ; $i++ ){
        $filename = pathinfo($array[$i], PATHINFO_BASENAME);
        if($current === $filename){
            $is_prev = true;
            continue;
        }
        if(!$is_prev){
            $prev = $filename;
            continue;
        }
    /* 2023/09/26 修正部分 */
        $next = $filename;
        break;
    }
}
?>
<!-- ▲▲ここまで追記▲▲ -->
<footer>
    <nav>
        <ul>
            <!-- ▽▽ここから追記▽▽ -->
            <?php echo isset($prev) ? "<li class='prev'><a href='{$prev}'></a></li>" :"";
            echo isset($next) ? "<li class='next'><a href='{$next}'></a></li>" :""; ?>
            <!-- △△ここまで追記△△ -->
            <li><a href="#">pagetop</a></li>
        </ul>
    </nav>
</footer>
</body>
</html>


それでは一つずつ見ていきます。

if(basename(getcwd()) === "novels")
こちらの条件分で、現在開かれているファイルがnovelディレクトリ以下のものであれば処理をするようにします。
getcwd()は現在のディレクトリを出してくれる関数で、今回のディレクトリ構成だと「サイトフォルダ/novels」まで出してくれます。
ルートからはいらないので、basename()を使いディレクトリが「novels」であるかどうか確認するようにします。

$array = glob("*");
glob()は指定したパス以下のファイルをすべて取得してくれる便利な関数です。
今回はnovelsディレクトリ以下のファイルで呼び出されていることを前提に、現在のディレクトリの中身のみ取得します。*(アスタリスク)で現在のディレクトリの中身をすべて取得してくれます。

$current = pathinfo($_SERVER['REQUEST_URI'], PATHINFO_BASENAME);
現在のファイル名を取得します。
pathinfo()は指定したパスからファイル名や拡張子などを取得してくれます。
$_SERVER['REQUEST_URI']はルートからファイルまでのパスを示しています。
PATHINFO_BASENAMEを第二引数に設定することで、ファイル名+拡張子のみを取得するようにします。
これにより$currentには「001.php」など現在開かれているファイル名のみが取得できます。
なお「.htaccess」などで拡張子を隠す処理をしている場合は、PATHINFO_BASENAMEPATHINFO_FILENAMEにするとファイル名のみで拡張子は抜いてくれます。

$is_prev = false;
for($i = 0 ; $i < count($array) ; $i++ ){
    $filename = pathinfo($array[$i], PATHINFO_BASENAME);
    if($current === $filename){
        $is_prev = true;
        continue;
    }
    if(!$is_prev){
        $prev = $filename;
        continue;
    }
  /* 2023/09/26 修正部分 */
    $next = $filename;
    break;
}


$is_prevは前ページがあるかどうかです。先にfalseで初期化しておきます。
ループで取得したファイルの数だけ処理を回します。
$filenameでファイル名+拡張子を取得し、その後は現在ファイル($current)と一致するかどうか判定します。
if($current === $filename):一致したら前ページの設定は済んでいるとして$is_prevtrueにしてから次のループへ移動します。
if(!$is_prev):一致していない且つ前ページの設定が済んでいなければ$prevにファイル名を設定し次のループへ移動します。
if ($i !== count($array) - 1):一致しない且つ前ページの設定は済んでいる、且つファイルが最後でない場合は次ページを設定してループを抜けます。
【2023/09/26修正】ページ数が3ページしか無いとき、2ページ目から3ページ目へのリンクが表示されない条件文だったので修正しました。
修正前は「最後のファイルでなければ次ページを設定」としていましたが、次ページを設定した時点でループを抜けるようにしました。


一番最初のファイル(001.php)には前ページがないので、ファイルが一致した時点で前ページ設定済みとみなし次のループへ行きます。そして次は002.phpファイルなので、次ページ設定の条件文に入り、次ページ設定をしてループを抜ける流れになります。
一番最後のファイル(004.php)であればループの回数とファイルの個数-1が一致して次ページを設定せずループを終了します。
(ファイルの個数は4つだけど配列では0から数えるので$iが3であれば最後のループということになります)

【2023/09/26修正】次ページが設定された時点でループを抜けるようにしたので、最後のページまで確認しないようにしました。
現在ページが最後のファイルと同じだった場合、if($current === $filename)を満たして次のループに行こうとしますがforの条件がページ数分回すことなのでループが終了します。
現在ページが最後のファイルでない且つ前ページの設定が済んでいる場合は、次ページを設定してループを抜けるように修正しました。


<?php echo isset($prev) ? "<li class='prev'><a href='{$prev}'></a></li>" :"";
echo isset($next) ? "<li class='next'><a href='{$next}'></a></li>" :""; ?>

isset()は値が設定されているかどうかの関数です。
NULLかどうかや空かどうかではなく、undefinedかどうかの違いです。
isset($prev)で前ページが設定されていたら"<li class='prev'><a href='{$prev}'></a></li>"で前ページのリンクを差し込みます。されていなければ何も表示しません。
同じようにisset($next)で次ページが設定されていたら"<li class='next'><a href='{$next}'></a></li>"で次ページのリンクを差し込みます。されていなければ何も表示しません。

処理まとめ
最終的にfoot.phpはこのようになります。
<?php
if(basename(getcwd()) === "novels"){
    $array = glob("*");
    $current = pathinfo($_SERVER['REQUEST_URI'], PATHINFO_BASENAME);
    $is_prev = false;
    for($i = 0 ; $i < count($array) ; $i++ ){
        $filename = pathinfo($array[$i], PATHINFO_BASENAME);
        if($current === $filename){
            $is_prev = true;
            continue;
        }
        if(!$is_prev){
            $prev = $filename;
            continue;
        }
        /* 2023/09/26 修正部分 */
        $next = $filename;
        break;
    }
}
?>
<footer>
    <nav>
        <ul>
            <?php echo isset($prev) ? "<li class='prev'><a href='{$prev}'></a></li>" :"";
            echo isset($next) ? "<li class='next'><a href='{$next}'></a></li>" :""; ?>
            <li><a href="#">pagetop</a></li>
        </ul>
    </nav>
</footer>
</body>
</html>


最後に
今回は高速化や桁を揃えていない連番を無視して実装してあります。
もし桁が不揃い場合はこちらの記事がわかりやすいので参考にしてみてください。
高速化については、個人サイトの範囲ならそこまで気にしなくていいかなとは思いますがglob()よりopendir()のほうが早い!というこちらの記事もあるので参考にしてみてください。
これで小説ページを追加するたびに前次リンクを追加しなくて済む!わーい!!と喜んでいるとーれでございました!

参考リンクまとめ
敬称略
php:pathinfo
二色人日記:【PHP】特定のディレクトリ内の連番が振られている画像を順番に出力する方法
あたまのなかがとっちらか~る:PHPでファイル一覧を取得するならglobよりopendirのほうが27倍早い
お久しぶりです!本当にお久しぶりです!
忙しい(メンタル)でなかなか更新できませんでした……。
この数ヶ月で色んなことを学び、どれもこれも記事にしたい気持ちと「このレベルで記事にしていいのだろうか…」な気持ちに挟まれていました。
今は落ち着いてきたので、「ええい誰がなんと言おうと”現在(いま)”の自分がタメになったなら記事にしてしまえ!!」と強気な気持ちになってきました。
これからまた記事を投稿できていけたらと思いますのでよろしくお願いします。

さて、てがろぐをXAMPPで確認したいっ!にてXAMPPの設定や使い方をご紹介しました。
こちらではhttp://localhost/site/からサイト別に分けられたフォルダを選択することでサイトの確認をしていました。つまりURLが「http://localhost/site/フォルダ名/index.html」のような形になるわけです。
しかし実際のサイト運営は「https://example.com/index.html」のようなドメインですよね。
なるべく実際の環境に近いほうが良いに決まってるっ!
あと最近、PHP触るようになってローカル用のドメイン使用がとても便利だと気づきました。
今回はローカル環境でもドメインっぽいものがつかえる、XAMPPのVirtualHostの設定方法をご紹介します!

この記事で最終的にできるコト
XAMPPのVirtualHostが使用できる。つまり、ローカル環境でドメイン(例:http://example.com/)によるアクセスができる。
なお、このやり方を使うとドメインでの確認が可能になりますが、スマホからの確認はまた別の設定をしないといけません。そこまで設定ができなかったので今回その方法は紹介しません。
予めご了承くださいませ。

今回の環境
  • Windows10
  • Google Chrome
  • XAMPP v3.3.0


準備
XAMPPの設定を変更していくので、オリジナルのバックアップは取っておきましょう。変更するのは下記のファイルです。
  • httpd.conf(xampp\apache\conf内)
  • httpd-vhosts.conf(xampp\apache\conf\extra内)
  • hosts(C:\Windows\System32\drivers\etc内)

てがろぐをXAMPPで確認したいっ!でhttpd.confのバックアップがある人はそれでも大丈夫です。

今回のディレクトリ構成
C:\
└xampp

D:\
サイト保管フォルダ
├サイトA/index.html
├サイトB/index.html
└サイトC/index.html
別のドライブにサイトデータを入れており、各サイトごとデータがフォルダに入っている状態です。
ドライブが同じでも大丈夫です。

XAMPPの設定
それでは早速設定をしていきます。

httpd.conf
VirtualHostを使用する設定をします。
520行目あたりに
# Virtual hosts
Include conf/extra/httpd-vhosts.conf

とあります。デフォルトで上記のようになっていたらこのままで大丈夫です。もし
#Include conf/extra/httpd-vhosts.conf
とコメントアウトされていたら使えるようにするため#を削除しましょう。

httpd-vhosts.conf
VirtualHostの設定をしていきます。
こちら開くと分かりますが、すべてコメントアウトされている状態です。
まず、20行目辺りに
#
# Use name-based virtual hosting.
#
##NameVirtualHost *:80

とありますので、
NameVirtualHost *:80
と最初の#を削除して使えるようにします。
これはポート80を使用するためのものです。今回はコメントアウトされているものをそのまま使いますが、必要に応じて数字を変更してみてください。

そこから下にはVirtualHostの例がコメントアウトで書かれています。「どこにあるファイルをルートとしてドメイン設定するか、エラーログは、アクセスログは」などの設定方法が書かれているものです。
今回はこのあたりまるっと無視します。
一番下の行に追記していきましょう。
<VirtualHost *:80>
    DocumentRoot "D:\サイト保管フォルダ\サイトA"
    ServerName localhost-siteA.com
</VirtualHost>
<Directory "D:\サイト保管フォルダ\サイトA">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Require all granted
</Directory>

こんな感じで追記しました。追加したいサイトの数だけ書きます。
一つずつ見ていきます。

<VirtualHost *:80>
httpd-vhosts.confで設定したポート番号をここに設定します。

DocumentRoot "D:\サイト保管フォルダ\サイトA"
ドキュメントルートとなるディレクトリまでのパスをここに入れます。サイトAフォルダの下にindex.htmlがあるので、サイトAまで設定すれば自動的にindex.htmlが表示されるようになります。

ServerName localhost-siteA.com
ここにURLに表示するサーバー名を記載します。
今回の場合、ここで設定することでhttp://localhost-siteA.com/へアクセスするとローカルにあるファイルを表示することができます。
ここでドメインまで付けるとChromeの場合アラートが出る可能性があります。アクセスに気をつけた方がいいような旨です。放置して大丈夫ですが怖い人はドメイン部分(.com)は消して設定するといいかも知れません。

<Directory "D:\サイト保管フォルダ\サイトA">
DocumentRootと同じパスを設定します。一致しないと動かないので注意!

Options Indexes FollowSymLinks ExecCGI
サイトアクセスに関わるオプション設定です。Optionsの設定がない場合はデフォルトで一つを除きすべて許可されているらしいです。が、レンタルサーバーによって許可されていないものもあるので、明示しておいたほうがいいかな?と思ってます。
Optionsの詳細はこちらが詳しいので細かく決めたい人は参照くださいませ。
今回記載したものについては
  • Indexes:ファイルが指定されなかった時、ファイルを一覧表示してくれる(indexファイルのみ指定がなくてもアクセスされるようになってます)
  • FollowSymLinks:シンボリックリンクがたどれます。それだけでなく.htaccessファイルでRewriteEngine onにしている場合、このオプションをつけないと403エラー(閲覧禁止)になります。例えば拡張子を削除している場合なんかはこのオプションが必要になります。
  • ExecCGI:CGIの実行ができます。てがろぐ利用の場合は必ず付けましょう。

今回私の環境では使わないので省きましたが、SSIを利用している場合はIncludesも追加しておきましょう。

AllowOverride All
.htaccessの設定をどれだけ反映させるか、みたいなやつです。詳細はこちらが詳しいので参照くださいませ。
今回はとくに細かく設定しなくて良さげだったので全部許可にしてあります。

Require all granted
アクセス制限に関する記述です。今回は全部OKにしてあります。
例えば「自分のPCからだけ!同一LANの他のPCからのアクセスは嫌!!!」といった場合はIPアドレスでアクセス制限などができます。
個人でやっている限りであればそこまで気にしなくていいのかな~とは思うのですが、たとえば「実は…マイクラサーバー持っててポート開放してるから色んな人がうちのLANに入ってくるんだ……」みたいな場合は設定したほうがいいかもしれないです。今回の記述だと誰でもオッケ~な設定なので、自衛の必要がある人は設定しましょう。
設定方法はこちらが詳しいです。

PCの設定
hosts
コマンドで打って変更するやり方もあるのですが、メモ帳などで変更したほうがやりやすいので私はその方法でやりました。
拡張子がついていませんが、メモ帳などに投げれば開かれます。
コメントアウトされているものは触らず、一番下に追記します。
127.0.0.1 localhost-siteA.com
コメントアウトされている例がこのIPアドレスなので、このアドレスをそのまま使いました。
アドレスの後ろには設定したサーバー名を記述します。
最後に保存して終了です!
ただし、メモ帳などで開くと「権限がないので失敗しました。管理者として再試行しますか?」といった表示されるかと思いますので管理者として保存するようにしましょう。

最終的な記述
変更箇所が多かったので、最後に今回の環境だとどういう記述になったのかさらっと載せます。

httpd.conf
# Virtual hosts
Include conf/extra/httpd-vhosts.conf


httpd-vhosts.conf
#
# Use name-based virtual hosting.
#
NameVirtualHost *:80

~中略~

<VirtualHost *:80>
    DocumentRoot "D:\サイト保管フォルダ\サイトA"
    ServerName localhost-siteA.com
</VirtualHost>
<Directory "D:\サイト保管フォルダ\サイトA">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Require all granted
</Directory>

<VirtualHost *:80>
    DocumentRoot "D:\サイト保管フォルダ\サイトB"
    ServerName localhost-siteB.com
</VirtualHost>
<Directory "D:\サイト保管フォルダ\サイトB">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Require all granted
</Directory>

<VirtualHost *:80>
    DocumentRoot "D:\サイト保管フォルダ\サイトC"
    ServerName localhost-siteC.com
</VirtualHost>
<Directory "D:\サイト保管フォルダ\サイトC">
    Options Indexes FollowSymLinks ExecCGI
    AllowOverride All
    Require all granted
</Directory>


hosts
127.0.0.1 localhost-siteA.com
127.0.0.1 localhost-siteB.com
127.0.0.1 localhost-siteC.com


これで「http://localhost-siteA.com/」や「localhost-siteA.com」にアクセスすればローカルにあるサイトが表示されます。

最後に
PHPでどうしてもドメインを取得したいときに、これまでの環境だと難しかったのですがこれでめでたく使えるようになりました。
単にてがろぐ使用だけならここまで設定しなくてもいいのですが、PHPなどサーバーサイドを記述していてもっと込み入ったことをしたい場合は是非ご参考くださいませ!

関連記事
てがろぐをXAMPPで確認したいっ!

参考リンクまとめ
※敬称略
XAMPP
てがろぐ(にししふぁくとりー)
Free Style:XAMPPでバーチャルホストを設定して複数のドメインを使う方法
buralog:【Apache】XAMPPでバーチャルホストを設定する方法
Qiita:XAMPPで任意のディレクトリをバーチャルホストにする方法
JavaDrive:Optionsディレクティブ:ディレクトリで使用可能な機能を設定する
           AllowOverrideディレクティブ:.htaccessを使った設定の上書きを許可する
           Requireディレクティブ:アクセスの許可や拒否などのアクセス制限を行う
フリーランスさばいばる:RewriteEngine onで403エラーの解決方法
お久しぶりの更新です!
最近少し忙しかったりイーガ団の相手をしていたりで滞ってしまいました。
良くも悪くも気楽にやれてる証かな?と楽観的に考えてます。
義務感でやると長続きしなくなってしまいますからね……(経験談です)

さて、GitHubActionsでWebサイトの更新を自動化したいっ!で当サイトもお世話になっているWitchServerのやり方は分かり次第、と載せていました。
やり方がわかったのはだいぶ前なのですがWitchServerさんで簡単てがろぐインストールができるようになったので、これに乗じて記事にしました。


WitchServerの対応に対応するてがろぐ制作者にしし様もやはりつよい……
それではさっそくやり方をご紹介しますっ!

今回の環境
・Windows10
・GitHub
・Sourcetree
・WitchServer

Actions secrets
暗号化の設定の仕方は前回を御覧ください。
設定する暗号化は以下の通りです。

①FTPサーバー
Name:FTP_SERVER
Secret:提供ドメイン
([契約時決めたもの].witchserver.netあるいは[契約時決めたもの].witchserver.net)
こちらの情報はコントロールパネルのご契約情報から確認できます。
20230521160224-admin.png

②FTPユーザー名
Name:FTP_USERNAME
Secret:FTPユーザー名

③FTPパスワード
Name:FTP_PASSWORD
Secret:FTPパスワード

FTPユーザーの追加はコントロールパネル「FTP設定」で追加できます。
デフォルトでは追加されていなかったはずなので、設定しておきましょう。
複数ユーザーを追加した場合、②と③は一致しなければ接続できないので注意が必要です。

yml
ここが一番の肝ですね!
WitchServerさんはFTPS通信のみ対応しているので、FTP Deployを利用したymlの記述方法も変わってきます。

まずは全文お見せします。
on: push
name: Deploy website on push
jobs:
  web-deploy:
      name: Deploy
      runs-on: ubuntu-latest
      steps:
      - name: Get latest code
        uses: actions/checkout@v3

      - name: Sync files
        uses: SamKirkland/FTP-Deploy-Action@v4.3.4
        with:
          server: ${{ secrets.FTP_SERVER }}
          username: ${{ secrets.FTP_USERNAME }}
          password: ${{ secrets.FTP_PASSWORD }}
          protocol: ftps
          server-dir: サーバーディレクトリ
          local-dir: ローカルディレクトリ


中身を見ていきます。
on: push
これは前回記述した
on:
  push:
    branches:
      - main

と同じ意味です。
前回は「mainブランチがプッシュされたら」とブランチを分けて使う場合を考えての記述でした。
もし別のブランチを利用している場合は、前回と同じ記述にします。
今回のこの記述は「すべてのプッシュに対して」動作します。
別途ブランチ設けていない場合は、一行で済みますということでご紹介しました。

- name: Get latest code
  uses: actions/checkout@v3

前回はv2を使用しました。FTP Deployはどうやら4.3.3以降を使う場合、v3を使わないと動作しないようです(参考:Deploy error on actions/checkout@v2)。
なので最新バージョン(2023/04/03現在)を利用します。

- name: Sync files
  uses: SamKirkland/FTP-Deploy-Action@v4.3.4

最新バージョンを利用しないとエラーを吐かれデプロイできません(4.3.3は未確認なのでわかりませんが…)。なので最新バージョンを利用します。
前回は@4.3.2の利用でした。今回のバージョンは@v4.3.4と「v」が入ってるのでお忘れないよう。
vを抜くと動作しません。

with:
    server: ${{ secrets.FTP_SERVER }}
    username: ${{ secrets.FTP_USERNAME }}
    password: ${{ secrets.FTP_PASSWORD }}
    protocol: ftps
    server-dir: サーバーディレクトリ
    local-dir: ローカルディレクトリ

server、username、passwordは前回と同じ記述です。
重要なのはprotocol: ftpsです。
FTP DeployはデフォルトがFTP通信なので、FTPS通信だと明示します。
これがないとWitchServerへはデプロイできません。必ず記述しましょう。

server-dirは/public_html/アップしたいディレクトリ名/を入れます。
コントロールパネルのドメイン設定から、デプロイしたいドメインのパスを記述してください。
local-dirは前回と同じで、設定しない場合はroot以下が対象です。

GitHub管理したいけどサーバー同期はしないファイルやフォルダがある場合は、excludeを記述します。そのあたりは前回記事にありますのでそちらをご覧ください。

上記ymlでWitchServerへデプロイできるかと思います。

注意点
0バイトファイルはActionsでアップロードしない
原因はわからないのですが、0バイトのファイルをあげるとエラーになります。
もし0バイトのファイルが入ったものをデプロイしようとすると、中途半端なデプロイになりサーバーに上がったファイルと上がらないファイルが発生します。
GitHubからActionsを確認すると以下のようなエラーが発生します。
Error: 139787667785600:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:308:
 (control socket) {
  library: 'SSL routines',
  function: 'ssl3_get_record',
  reason: 'wrong version number',
  code: 'ERR_SSL_WRONGVer 4.0.0NUMBER'
}
Error: Error: 139787667785600:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:308:
 (control socket)

こちらのIssueで「0バイトファイルのせいだったみたい!OpenSSLのバグかも?」とコメントがあったので0バイトファイルを除外したら無事デプロイできました。ただ本当にOpenSSLのバグかどうかは不明です。
なお、GitHubにあげるだけなら大丈夫だと思うのでymlにexcludeを追記し0バイトファイルをアップロードしないやり方も使えると思います。

「0バイトファイルって空っぽじゃん。そもそもあげなくない?」と思うでしょう。
配布プログラムなどを利用している方は、ディレクトリ内に0バイトファイルがある可能性があります。
私の場合は、do様配布のいいねボタン改を利用しており、その中に0バイトファイルがあったことから発生したエラーでした。
いいねボタン改を利用している方は、いいねぼたん改フォルダ内のdatas > setting > deny.datはFTPツールで別途サーバーへアップロードしたほうが良いかと思います。
FTP DeployはこのActionsを使ってアップロードしたものを管理しているので、FTPツールで別途アップロードしたファイルは対象外になります。
いいねボタン改の中身をいじっていなければ、いっそこちらのファイルまるまるGitHubではなくFTPツールで管理したほうが楽かもしれないですね。
一度設置すればあとはアップデート以外触ることはほぼ無いと思うので、GitHub管理の対象にしなくても良さそうと個人的には思います。

たまに失敗する
エラー文章を残してないので申し訳ないのですが、たまにデプロイに失敗します。
毎回ではないのですが、CORESERVERやリトルサーバーは失敗したことないので比較するとたまに程度ではありますが失敗します。
その場合はGitHubのActionsから手動で再度実行すると成功します。
今後エラーが分かり次第こちらに記載します。

デプロイできるようになるまでに発生したエラー
下記のエラーは①protocolをftpsに指定 ②最新バージョン利用で解決したものです。
なのであまり参考にはならないかも知れませんが、自分のためにも載せておきます。
ちなみに失敗しまくってるのがこの画像からわかります。
何かと失敗しまくった残骸
何かと失敗しまくった残骸

テストで別ドメインで試したりもしたので画像のがすべてではないのですが、まあまあ苦戦しました。

エラー① protocol未指定
FTPError: 530 Non-anonymous sessions must use encryption.
    at FTPContext._onControlSocketData (/home/runner/work/_actions/SamKirkland/FTP-Deploy-Action/4.3.2/dist/index.js:5254:39)
    at Socket.<anonymous> (/home/runner/work/_actions/SamKirkland/FTP-Deploy-Action/4.3.2/dist/index.js:5095:44)
    at Socket.emit (events.js:314:20)
    at addChunk (_stream_readable.js:297:12)
    at readableAddChunk (_stream_readable.js:268:11)
    at Socket.Readable.push (_stream_readable.js:213:10)
    at TCP.onStreamRead (internal/stream_base_commons.js:188:23) {
  code: 530
}
Error: FTPError: 530 Non-anonymous sessions must use encryption.

FTPが暗号化していない仕組みなこともあり「暗号化せい」というようなことを言われてます。
protocolをFTPSにしたらこのエラーは消えました。
※前回記事のymlでやって失敗してます。

エラー② タイムアウト
Error: Timeout (control socket)
    at Socket.<anonymous> (/home/runner/work/_actions/SamKirkland/FTP-Deploy-Action/4.3.2/dist/index.js:5288:58)
    at Object.onceWrapper (events.js:420:28)
    at Socket.emit (events.js:314:20)
    at Socket._onTimeout (net.js:483:8)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)
Error: Error: Timeout (control socket)

protocolにFTPSを追加して試したもの。初動だと全データアップロードするのでどうしても時間はかかってしまうが、タイムアウトするほどの量ではない。が、タイムアウトと言われたからには時間がかかりすぎていたのかも知れない…。
この時点ではcheckoutはv2、FTP Deployは4.3.2でやってます。
最新バージョンにしたらタイムアウトしなくなりこのエラーも出なくなりました。
最新バージョンは未指定だと30000ミリ秒=30秒でタイムアウトします。なので過去バージョンはもっと短かったか、サーバー側から切られたからのどちらかが原因かなと考えてます。

エラー③ ネットワークストリームの読み取りに失敗
FTPError: 426 Failure reading network stream.
    at FTPContext._onControlSocketData (/home/runner/work/_actions/SamKirkland/FTP-Deploy-Action/4.3.2/dist/index.js:5254:39)
    at TLSSocket.<anonymous> (/home/runner/work/_actions/SamKirkland/FTP-Deploy-Action/4.3.2/dist/index.js:5095:44)
    at TLSSocket.emit (events.js:314:20)
    at addChunk (_stream_readable.js:297:12)
    at readableAddChunk (_stream_readable.js:268:11)
    at TLSSocket.Readable.push (_stream_readable.js:213:10)
    at TLSWrap.onStreamRead (internal/stream_base_commons.js:188:23) {
  code: 426
}
Error: FTPError: 426 Failure reading network stream.

これがとてつもなく苦労した。
同じ問題を抱えたIssueで「このエラーは特定のホスティングサービス(サーバーのことだと思われる)で発生するみたい」のコメントや、vsftpd(FTPの相手をしてくれるサーバー側のプログラム)で同じ問題が起こるコメントもあり、さらにvsftpdを調べていくとvsftpdでSSL/TLS(暗号化技術の1つ。FTPSのSの意味がこれ)を利用するには設定が必要で~~とかApacheの設定をいじると使える~~~とか……
要するに、サーバー側の設定の問題でこちらではどうしようもないこと、なのだろうと解釈してます。
ただ、FTP Deployのバージョンを最新バージョン(4.3.4)にしたらこのエラー出なくなりました。
サーバーサイドは未履修なので結局の原因は分からずじまいなのがもやもやするものの、ひとまず動いたのでよしとします。

最後に

些細な独り言を拾ってくださる、まさに「サポートの手厚い」サーバーさんです。
ちなみにツイートの件は上記エラー③のことで解消されたと報告済みです。その後のレスもありご丁寧に対応していただきありがたい限りです。
冒頭でお伝えしたてがろぐについてもそうですが、最近技術ブログを開始されました。

こちらの記事の中をみたところ、色んなサイトでお見かけする「phpを使うと共通部分楽に管理できるよ!」と言った内容だけでなくSSIやJavaScript、jQueryでのやり方まで載せてくださっています。
ローカルでphpの確認が難しい環境でのサイト運営の場合、JavaScriptやjQueryでのやり方が分かればとても助かりますよね!
こうした側面からもWitchServerさんは個人サイト運営者に寄り添ってくれる素晴らしいサーバーさんですので、ぜひおすすめします。

関連記事
GitHubActionsでWebサイトの更新を自動化したいっ!

参考・リンクまとめ
※敬称略
WitchServer
WitchServer てがろぐ設置マニュアル
魔導書と杖 WitchServer公式技術ブログ
てがろぐ WitchServerでのセットアップ手順
FTP Deploy
Deploy error on actions/checkout@v2
FTP Deploy checkoutバージョンエラー
FTP Deploy 0バイトエラーIssue
FTP Deploy ネットワークストリーム読み込みエラーのIssue
do
いいねボタン改
.htaccessやサーバー設定でBasic認証ができるわけですが、ブラウザからIDやパスワードを求められるとちょっとびっくりします。
昔そういう個人サイトを見たことがあるのですが、フォレストやnanoなどの認証ばかり触れていたせいでブラウザからの認証に「なんだこれ!怖い!」と避けていた記憶が蘇ります。
サイトを運営する立場になった今ならあれはそこまで恐れるものでもないとわかるのですが、せっかくならログイン周りもデザインしたいところ・・・
個人サイトで入り用だったのもあり、JavaScriptで簡単なログイン認証を自作してみました!
今回はログインに焦点を絞りましたが、流用すればログインに限らないパスワード認証にも使えると思います。

デモ
こちらのデモページから動作確認ができます。
仕様
①indexページでパスワード認証
成功:コンテンツページへ飛ぶ
失敗:「パスワードが違います」と表示

②ログインに成功したら、次回以降パスワードは自動入力
 今回はパスワード保存の期限を設定していないので、使用したライブラリのデフォルト期間(365日)はCookieで保存されます。

③ログインしていない状態でindex以外のページへいったら、内容を隠してログイン画面をポップアップ表示
成功:ポップアップが消えて中身が見える
失敗:画面はそのまま「パスワードが違います」と表示される

④ログインしていればindex以外のページへ直接いってもログイン画面が出ず中身を見れる

⑤コードからパスワードが読まれないようハッシュ化
暗号化:暗号化されたデータを元のデータに戻せるタイプ
ハッシュ化:暗号化されたデータは元のデータに戻せない

こんな感じですね。
こちらの作り方を解説していきます~

準備
  • jQuery…jquery-cookieのために必要です
  • jquery-cookie…jQuery用いたCookie操作用
  • jsSHA…パスワードのハッシュ化用

ハッシュ化はjsSHAを使います。
「Newest Release / Download」のGitHubにリンクがあるので、そこからDLページへ飛びます。
Source code(zip)かSource code(tar.gz)のどちらかを選んでDLしてください。
いろいろなファイルが入っていますが、必要なのは「jsSHA-3.3.0/jsSHA-3.3.0/dist」にあるsha256.jsファイルだけです。

ファイル構成
index.html
contents.html
css/style.css
js/
├login.js
└3rd/sha256.js
さきほどDLしたsha256.jsをこの位置に入れます。
自分が作ったものと区別できるよう3rdフォルダに入れていますが、パスが通っていればどこでもOKです。
login.jsにログインの処理を書いていきます。

JavaScriptの読み込み
まずJavaScript周りの読み込みしておきましょう。
ログイン認証したいページやログインしていなければ中を見せたくないページに各種読み込んでいきます。
今回だとindex.htmlとcontents.htmlですね。
htmlファイルのbodyの閉じタグ直前に下記を記述します。
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.4.min.js" integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous"></script>
<!-- 3rd -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>
<script src="js/3rd/sha256.js"></script>
<!-- script -->
<script src="js/login.js"></script>

jQueryのCDNはこちらをコピペしてます。
今回はjQuery Core 3.6.4 minifiedを使いました。
配布プログラムを利用していてjQueryを入れてるよ!ということであればそちらを使うのが良いかと。

jquery-cookieのCDNはこちらの最新版を使ってます。
今回はVersion1.4.1を使いました。URLが2つありますが下の方を使ってます(どちらでも大丈夫です)。

sha256.jsは準備項目でDLしたファイルです。
login.jsはログイン周りの処理を書くファイルです。

index.html
ログイン周りに必要な部分だけ抜粋します。
<div id="loginResult">パスワードが違います</div>
<div>
    <input type="password" placeholder="password" id="loginPass">
    <input type="button" value="送信" id="login">
</div>

loginResultにはパスワードが異なるときの文章を記述します。
inputdivタグで囲っていますが、これはformにするとエンターキーでsubmitになってしまうことからdivにしてます。そのあたりの処理(エンターキーで認証処理を実行)を書けるようであればformでもOKかと!

そしてパスワードを入力するのが
<input type="password" placeholder="password" id="loginPass">
の部分です。type="password"で伏せ字にしてますがtype="text"でもOK。

パスワード認証の処理は
<input type="button" value="送信" id="login">
のクリックで実行するようにします。

contents.html
今回はわかりやすいようにcontents.htmlの名前になっていますが、ログインしないと見れないファイルに記述する内容です。
まずログインするまでぼかしておきたいタグにclass="passcheck"というクラスを追加します。
bodyに追加するとログイン用のポップアップもぼかしてしまうのでbodyに入れないようにします。
例えば
<body>
    <header class="passcheck">
        <!-- ヘッダーの記述 -->
    </header>

    <main class="passcheck">
        <!-- ここにコンテンツの記述 -->
    </main>
    
    <footer class="passcheck">
       <!-- ここにフッターの記述 -->
    </footer>

    <!-- 各種scriptの読み込み(省略) -->
</body>

といった感じです。
ぼかさなくていいなってものがあればクラスを外してください。

次にログイン用のポップアップを記述します。
<div class="overlay">
    <div class="popup-window">
        <h2>Login</h2>
        <div>
            <div id="loginResult">パスワードが違います</div>
            <div>
                <input type="password" placeholder="password" id="loginPass">
                <input type="button" value="送信" id="login">
            </div>
            <a href="index.html">indexへ</a>
        </div>
    </div>
</div>

index.htmlへ戻るリンクはindexページへ戻れるように貼ってます。不要なら削除してOK。
必ずpasscheckの外側に記述してください
demoだと下記のようにmainタグとfooterタグの間に記述してます。
<main class="passcheck">
    <!-- ここにコンテンツの記述 -->
</main>

<!-- ログイン用ポップアップ -->
<div class="overlay">
    <div class="popup-window">
        <h2>Login</h2>
        <div>
            <div id="loginResult">パスワードが違います</div>
            <div>
                <input type="password" placeholder="password" id="loginPass">
                <input type="button" value="送信" id="login">
            </div>
            <a href="index.html">indexへ</a>
        </div>
    </div>
</div>

<footer class="passcheck">
    <!-- ここにフッターの記述 -->
</footer>


css
#loginResult#loginResult.error.overlay.popup-windowを記述していきます。

ログイン失敗表示
#loginResult{
    display: none;
    /* 下記はデザイン用 */
    padding: 10px;
    margin: 10px auto;
    width: 80%;
    border: 1px solid transparent;
}

#loginResult.error{
    display: block;
    /* 下記はデザイン用 */
    border-color: #de9a9a;
    background: rgba(222, 154, 154, 0.25);
}

デフォルトは非表示で、errorクラスを追加したら表示するようにします。

ポップアップ
.overlay {
    display: none;
    position: fixed;
    z-index: 9999;
    width: 100%;
    height: 100vh;
    top: 0;
    left: 0;
    background: rgba(0, 0, 0, .5)
}

.popup-window{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    /* 下記はデザイン用 */
    width: 90vw;
    max-width: 380px;
    padding: 20px 0;
    background: #3a3a3a;
}

デフォルトは非表示です。表示処理をJavaScriptで行います。

そしてぼかし用のクラスです。
.blur {
    filter: blur(10px);
}


login.js
ここが要ですね!
まずスクリプトを書いていく前にパスワードを用意します。
SHA256に変換してくれるサイトでSHA256変換したパスワードを用意します。
わかりやすさからこちらのサイトで用意しました。出力形式は小文字です。
今回使うライブラリのjsSHAページにあるデモを使ってもいいでしょう。
その場合はHasing Demoの欄に以下の設定で出力します。
Input Text: パスワードにしたい文字列を入力
Input Type: TEXT
SHA Variant: SHA-256
Number of 1
Rounds: Output Type: HEX
Output Hashに出力された文字列がハッシュ化されたパスワードです。

login.jsに記述するコード全文はこちらです。
$(function(){
    const PASS_HASH = 'さきほど出力したハッシュ化されたパスワード';

    /* index.htmlでない且つCookieのハッシュ化パスワードが異なっていたら
       passcheckクラスにぼかしをつける+ポップアップを表示 */
    if(!location.pathname.includes('index.html') && $.cookie('loginhash') != PASS_HASH){
        $('.passcheck').addClass('blur');
        $('.overlay').show();
    }
    
    /* Cookieにログインパスワードが残っていたら自動入力 */
    $('#loginPass').val($.cookie('loginpass'));

    /* ログインボタンをクリックしたら認証処理 */
    $('#login').click(function() {
        const pass = $('#loginPass').val();
        const shaObj = new jsSHA('SHA-256','TEXT');
        shaObj.update(pass);
        const hash = shaObj.getHash('HEX');
        if (PASS_HASH === hash) {
            /* 入力されたパスワードが合っていたら、Cookieに保存 */
            $.cookie('loginpass',pass);
            $.cookie('loginhash',hash);
            if(location.pathname.includes('index.html')){
                /* index.htmlにいたらコンテンツページへ飛ぶ */
                window.location.href = 'contents.html';
            }else{
                /* index.htmlでなければ、ぼかしを消してポップアップを非表示 */
                $('.passcheck').removeClass('blur');
                $('.overlay').hide();
            }
        }else{
            /* パスワードが不一致なら「パスワードが違います」のエラー表示 */
            $('#loginResult').addClass('error');
        }
    });
})

.htaccessで拡張子を表示しない設定をしている場合location.pathname.includes('index.html')の拡張子も消してください。
セキュリティ的にはまだまだかと思いますが、パッと見でパスワードがわからないくらいにはなってるかなと思います。
もっとしっかりやるならパスワード管理用のファイルを用意したほうがいいのですが、そこまでガチガチじゃないくていいかなというのと、ファイル読み込みなどの処理が面倒だったので省きました。

最後に
phpで作ってみようかな~と思ったのですが、ちょっとまだ勉強不足で時間がかかりそうだったのでJavaScriptで作りました。
ゆくゆくはきちんと中身が見られないようパスワード用のファイルを用意したり、パスワードの設定そのものをできるようにしたいところ・・・
とりあえずなものではあるものの、割と悪くないんじゃないかな?と個人的に思ってます。
上手く出来ると楽しい~~!

参考
【超シンプル】ポップアップをHTMLとCSSだけで実装する
JavaScriptを理解したいっ【変数編】の続きです。
前回はvarletconstについて学びましたので、今回は命名について勉強していきます。

命名規則
JavaScriptの命名での条件は以下のとおりです。
  • 1文字目は英字、_(アンダースコア)、$(ドル記号)のいずれかであること
  • 2文字目以降は1文字目で使える文字、もしくは数字のいずれかであること
  • 変数名に含まれる英字の大文字・小文字は区別される
  • JavaScriptで意味を持つ予約語ではないこと

このあたりはC系言語でも同じ…$を命名で使える…のか…?
C系で$を命名に使ったのを見たことがなく、C#で試してみたら案の定エラーが出ました。JavaScriptだから使えるのかな……?

さて、変数、関数、classなど任意に名前を付けられるものは規則性が重要になってきます。
これは別に上記の条件さえ満たせば「こういう規則で名前をつけろ!」と厳密に決まっているものではありません。
個人サイト運営のなかでの命名は、自分だけが使うものであれば自分がわかればいいかなと思います。とはいえ「3日前の自分が書いたプログラムは他人が書いたと思え」と持論があるので(もしかしたら誰の言葉かもしれない)、今の自分がわかるからと横着して適当な命名をすると後々痛い目を見ます。尚、経験談。
未来の自分が分かるプログラムを書くために、命名規則を自分の中で定めてみよう!

可読性を重視
JavaScriptに限らずどの言語でも恐らく同じだとは思いますが、ある程度共通認識があります。
  • 記法を統一する
  • 名前からそれが何であるか分かりやすくする
  • 長すぎず、省略しすぎない
  • 基本的に英単語を使う

「名前からそれが何であるか分かりやすい」「長すぎず、省略しすぎない」「基本的に英単語を使う」は基本として知っていたのですが、記法について私の知ってるものと少し異なっていたのでそのあたりを深掘りしていきます。
なお、記法は複合語で使用するものです。

camelCase記法
camelCaseはキャメルケースと読みます。
camel=ラクダでラクダのコブのように「最初の単語の頭は小文字、次以降の単語の頭は大文字」というルールの書き方です。記法名のcamelCaseと同じ書き方ですね。
例えば「名前をセットする」目的のデータにcamelCaseを適応するとsetNameとなるような感じです。
恐らく一番よく使われる記法なのではないでしょうか?
C系言語に触れていたときは、変数名は基本的にこのcamelCase記法でした。
※開発現場やプログラマーによります。

Pascal記法
プログラム言語PascalにちなんでいるらしいこちらのPascal記法。Pascal=パスカルです。
単語の頭は大文字にする書き方で、先程のsetNameをPascal記法にするとSetNameになります。「JavaScript」「Perl」という単語もPascal記法ですね。
C系言語に触れていたときは、クラス名や関数名などをこの記法で書いていました。
全体の統一性から変数名をPascal記法で書いた時もありましたが、変数名か関数かの区別をつきやすくするため、変数名はcamelCase記法、関数・クラス名はPascal記法で統一するようになりました(私個人の話です!)
テンプレートに同梱しているJavaScriptを眺めてるとPascal記法を見かけないので、この記法はマイナーなのかな?と感想を抱いています。

アンダースコア記法
単語と単語の間に_(アンダースコア/アンダーバー)を挟むこの記法。
私は「snake case記法」と覚えていたので言語によって言い方が異なるのかも知れません。
setNameだとset_nameSET_NAMEなどになります。
C系言語に触れていたときは、定数での命名は大文字+アンダースコア記法でした。
例えば#define WINDOW_WIDTH 1920とか#define WINDOW_HEIGHT 1080とか(C++ではconstではなく#defineで定数を設定することもできます)。この定数なら画面幅と画面高さを指定しているのが分かりますね。
JavaScriptだとconst WINDOW_WIDTH = 1920;const WINDOW_HEIGHT = 1080;となるでしょう。
参考にしている書籍だと「一般的に定数名で使用」とあるので、そのあたりは私の認識と共通していそうです。

JavaScriptライブラリjQueryを参考にしてみる
とってもお世話になっている便利ライブラリ「jQuery」の中身を見て、どんな命名規則なのか読み解いてみます。

変数名
jQuery v3.6.4 抜粋(48~71行目)
var arr = [];
var getProto = Object.getPrototypeOf;
var slice = arr.slice;
var flat = arr.flat ? function (array) {
    return arr.flat.call(array);
} : function (array) {
    return arr.concat.apply([], array);
};
var push = arr.push;
var indexOf = arr.indexOf;
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
var fnToString = hasOwn.toString;

命名を見ていくので処理内容は省略します。
var arr = [];は配列定義ですね。arr=arrayの省略でしょう。
この省略は意味がわかるので使えそうです。

var getProto = Object.getPrototypeOf;はcamelCase記法なのがわかります。getは取得なのでProtoを取得した変数だと分かります。

var flat = arr.flat ? function (array) {
    return arr.flat.call(array);
} : function (array) {
    return arr.concat.apply([], array);
};
これはif文を使わない条件分岐の書き方です。
arr.flatが真なら
function (array) {
    return arr.flat.call(array);
}
を実行し、arr.flatが偽なら
function (array) {
    return arr.concat.apply([], array);
}
を実行するというものです。C系でも使いますね。
条件分岐の中身が少ない場合はこの書き方がスマートなのでお気に入りです。
……脱線してしまった。

var indexOfvar toStringvar hasOwnvar fnToStringでもcamelCase記法ですね。
indexOfは「配列の何番目か」、toStringは「文字列に変換」、hasOwnは「自身を持つかのフラグ」、fnToStringは「関数を文字列に変換」、といったところかなと思います。
indexOfやtoStringはC#でも使ったことがあるのですんなり意味を読み取れました。
JavaScriptは関数を示すときfunctionを記述するので、functionを省略してfnということでしょう。この省略の仕方も使えそうです。
ちなみにC#やC++は戻り値なしの関数を記述するときはvoidから始まります。
JavaScriptは戻り値があろうがなかろうがfunctionで指定できますが、C#やC++では戻り値がある関数を書きたいときは戻り値と同じデータ型で書き始める必要があります。
そう考えるとfunction万能すぎでは……?

var class2typeは「classをtypeで」といったところでしょうか。
「数字を文字列で」などのような変換系の命名ではnumberToStringではなくnumber2stringのように「2」を使って表すことがあります。number2stringのnumberやStringもnumやstrで省略しても分かりそうなのでnum2strでも良さそうです。
camelCaseでいくならclass2Typeでは?と思ったのですが、読みやすさ重視でclass2typeなのかもしれません。変換系のデータが他になかったので確認できませんでした。まあ読みやすいのでclass2typeがいいですね。

var toStringvar 2stringでないのは変数名の頭に数字は使えないからでしょう。

以上から、
  • 変数名は基本的にcamelCase記法
  • array、functionなどはarrやfnと省略
  • 変換系は「2」で挟みすべて小文字でcamelCase記法から外れる

だと分かりました。
ここまでやっておいてあれですが、「そもそもJavaScriptにある変数見れば早いのでは」と気づきました。
ということで事項関数名はJavaScriptの方を見ていきます。

関数名
JavaScriptの関数についてはなかなか特殊な書き方をすることがあるので関数についても勉強したいところ……。
document.getElementById()document.querySelector()からみても分かる通り、JavaScriptとして関数名はcamelCase記法の模様。
一応jQueryの中身も見てみたのですが、JavaScriptにラップ(元の機能やデータに機能やデータを追加したり削除したりして、同じ名前でも元とは別の内容で処理すること)してる形がほとんどっぽかったので省略します。

最後に
これまでを踏まえ、「変数名」「関数名」はcamelCase記法で今後は記述を心がけていこうと思います。
参考にした書籍によると定数をアンダースコア記法のが一般だそうです。C#やC++と同じですね。
お借りしたり作っていただいたりしたテンプレートに同梱されているJavaScriptファイルを見ると、基本的にcamelCase記法で統一されているみたいでした。テンプレート利用のサイトで使うJavaScriptはひとまずそちらに合わせていきます。
ただまあなるべくたくさん見て触れたほうが自分のためになるはずなので、いつもお世話になっているサイト様以外の、別のサイト様のテンプレートも勉強として見漁る予定です。
とりあえずまずは数年積み本にしてるリーダブルコードをちゃんと読みます!
目指せ!読みやすいコード!!

関連記事
JavaScriptを理解したいっ【変数編】

参考
改訂新版JavaScript本格入門モダンスタイルによる基礎から現場での応用まで
※私が参考にしたのは2019年発行のものですが、最新版があるのでご購入の際は最新版(改訂3版JavaScript本格入門
~モダンスタイルによる基礎から現場での応用まで
)が良いかと思います。
C#畑にいたころ、「C#とJavaScriptは似てる」というような話をたびたび聞きました。
有名なゲームエンジンUnityがかつてサポートしていた言語がC#とJavaScriptであったこと(※現在UnityはC#のみです)もあり、C#とJavaScriptは似てると先入観のまま触れるようになりました。

初めて見たJavaScriptのソースがjQuery使用のものだったので、
「全然違うじゃん!!なんだこの表記!!」
とたじろいだ記憶があります。
jQuery特有の記載方法であり、JavaScriptがすべてあの書き方ではないと今なら分かります。
実際JavaScriptに触れてみて
「ある程度基本的な部分はどの言語も恐らく同じ。配列の扱いは確かに似ているかもしれない」
と感想を抱きました。

とはいえ、言語が違えば”常識”も違う。
雰囲気で使っているあれこれを、C系言語と比較しながら今一度きちんと勉強して理解するぞ!おー!!
※記事が長くなったので命名については分けます。

変数宣言
JavaScriptで変数宣言するとき
varletconst
の3種類の命令から始まります。
違いをそこまで理解できていなかったので、まずはここからお勉強。

var
C#にも型推論のvarがあるので同じものだと思ってました。C++だとauto。
JavaScriptのvarもおおよそ挙動は同じ。
ただし、なんとこやつグローバルで宣言でき初期化しなくてもエラーにならず、しかも同じ名前で何度も宣言できてスコープ内で宣言したものを外でも使えるのである!
分かりますか奥様!この驚きたるや。

例えばC#で以下のように記述してみる。
エントリポイント(ソースが実行される開始点)が必要な関係上class内に入れている
class Program
{
    var test;

    static void Main()
    {
        var test2;

        var test3 = 0;
        var test3 = 2;

        var test4 = 0;
        test4 = 4;

        var test5 = 0;
        for (int i = 0; i < 10; i++)
        {
            test5++;
        }

        var test6 = 0;
        Console.WriteLine("test6は" + test6 + "です。");
    }
}

上記だと、test4~test6以外はエラーになる。
20230415223958-admin.png

これをJavaScriptで書き直してみよう。
classは一旦おいておく
var test;

function Main()
{
    var test2;

    var test3 = 0;
    var test3 = 2;

    var test4 = 0;
    test4 = 4;

    var test5 = 0;
    for (var i = 0; i < 10 ; i++) {
        test5++;
    }

    var test6 = 0;
    console.log("test6は" + test6 + "です。");
}

JavaScriptはなんとエラーにならない!!
202304152239581-admin.png
しゅごい……。
この挙動はJavaScript特有のものらしく、「巻き上げ」と呼ぶそうです。脳内でへえボタン連打しました。へえボタン…分かるかな…ハハ。
とはいえ、C#扱っていた頃はデータ型きっちり書きたいマンでvarを使う習慣がさほどなかったので、JavaScriptで記述する際にintを使おうとしてエラって「intがない…だと…?」と困惑した記憶があります笑
varの再宣言ができて便利だなと思う一方、
変数を簡単に書き換えられてしまうと、意図しないバグが発生する
letやconstに比べて、varは巻き上げ時のバグを生み出しやすい

記事を見つけたので肝に銘じます。

スコープ内で宣言したものを外でも使えるのスコープとは、for(条件文){...}if(条件文){...}など{ }で囲まれた部分のことを言います。
これがね…実に気持ち悪い面白い動きなんですよね。
C#でスコープ内で宣言した変数をスコープ外で使おうとするとエラーが出ます。
20230415233236-admin.png

JavaSciptさんはなんとえらーがでないんですねぇ。
202304152332361-admin.png

宣言以降も使えるというのはなんやかんや使いやすいんだろうなとは思います。ちょっと私はまだ慣れないけれど、必要になったところから宣言できるのは、「この宣言した変数どこから使い始めてるんだ?」となるよりソースの可読性が高くなると思えばいいものなのかもしれません。

let
Let It Go が思い浮かぶほど馴染みないものでした。なんやこれ。
なので実はあんま使ってなかった。これからきっと使いこなせるはず…!
varと使い方が似ているletの特徴は同じ名前の変数を作れないブロックスコープを意識していることです。
前項varで分かる通り、私が過去触れた言語(C、C#、C++など)は同じ名前の宣言ができません(別同士のブロックスコープであれば名前が同じでも可。ブロックスコープについては後ほど)。
なので私からするとletのほうが馴染みがあるものでした。びっくり!
ただまあ、例えば「タグ内のテキストを取得したい」とかだと変数名をtextとかにするのが分かりやすくて楽だし何かと多用してしまいそうなので、jsファイル内に1つだけの変数にしたいときに使うのがいいのかな?とか思いました。
…いや、下手なこと言っちゃいけないな…ううむ…

2つ目のブロックスコープを意識しているに触れていきます。
「ブロックスコープ?」と初めは疑問でしたが、C系時代は「当たり前すぎて一周回って意識しない」感じのものでした。
ブロックスコープとは{}で囲まれた領域内のことを指します。
昔はブロックレベルはなかったそうですが、ES2015(2015年に標準化されたJavaSciptの規格ECMASCriptのこと。6版であるためES6と呼ばれていたらしい)で新しくブロックレベルが追加されました。letが使えるようになったのもこのときです。
varではfor文やif文内で宣言した変数を外でも使えましたが、letは使えない…個人的に挙動としてはこちらのほうがしっくり来ます。

letもvarもデータの上書きが可能なので、どう使うのが良いかいろんなプログラム見てもう少し勉強が必要そうです。

const
これはC#やC++にあるのと同じものでした。
データ型の宣言がない点では違和感を覚えますが、JavaScriptはそういうものなんですね。
constは定数です。定数とは「値が変わらないもの」のことです。
サイトで使うJavaScriptはあまり数字が出てこない印象があるのですが、ゲームプログラムだと数字がたくさん出てきます。パラメーターあたりなんかは数字祭りですね。
プログラムを打つ中で数字を扱うとき、原則として数字の意味を明確にしなければなりません。パッと見てなにを表すかわからない数字のことをマジックナンバーといいます。魔法の数字、でもすっごく嫌われる数字です。初期化で使う0は例外だとは思いますが。
例えば、jQueryを使い「速度500ミリ秒(0.5秒)のスクロールアニメーションを実装しよう」とします。
当サイトでのやり方だと
$('a[href^="#"]').click(function () {
    let href = $(this).attr("href");
    let target = $(href == "#" || href == "" ? "html" : href);
    let position = target.offset().top;
    $("body,html").animate({ scrollTop: position }, 500, "swing");
    return false;
});

になるわけですが、上記だと「500」の数字がマジックナンバーです。
「なんの処理か分かるし500が何を意味してるか分かるから別にこのままでもいいんじゃ?」
と思うでしょう。自分ひとりで好きなようにやっているのであればそれでもかまわないと思います。
ただ、他に使う人がいる場合はたとえ相手が意味をわかったとしても定数化しておくべきでしょう。
上記のコードであれば
$('a[href^="#"]').click(function () {
    const animSpeed = 500;
    let href = $(this).attr("href");
    let target = $(href == "#" || href == "" ? "html" : href);
    let position = target.offset().top;
    $("body,html").animate({ scrollTop: position }, animSpeed, "swing");
    return false;
});

と言った感じにするのがいいかな?と思います。
横着してclickイベント内でconst宣言していますが、もし全体的によく使うものであればconstの宣言はファイルの一番最初にやるのが定石かなと思います。(C系で語ってるけどJavaScriptもそうだよね…?)
constで宣言されたものはデータの書き換えができません。これがvarやletとの大きな違いでしょう。
C系で使うときはデータ型が必要なのでconst float TAX = 1.1;みたいな使い方ですが、JavaScript はデータ型宣言がなくとも使えるので数字以外にタグやセレクタでも使えますね。(例:const TAX = document.getElementById("TAX");
何度も使うタグはconstで定義しておくと楽だと思います。

最後に
個人サイトを作った当初はなんとな~く「動けばいいや」と開設や運営に重きをおいていました。今ではJavaScriptで実装したいことがあればある程度自力で書けるようになったと思います。
そんな今だからこそ、基礎的な部分を学び直せば理解が深まるのではと(諸事情で買った)本を開きました。
まだまだ序盤しか読めていませんが、今の私にはちょうどよく分かりやすいので本で学んだことを自分の考えを添えて記事にしていこうと思います。
JavaScript勉強の旅は始まったばかりであるっ!

関連記事
JavaScriptを理解したいっ【命名編】

参考
JavaScriptでvarが非推奨な理由を整理してみた
改訂新版JavaScript本格入門モダンスタイルによる基礎から現場での応用まで
※私が参考にしたのは2019年発行のものですが、最新版があるのでご購入の際は最新版(改訂3版JavaScript本格入門
~モダンスタイルによる基礎から現場での応用まで
)が良いかと思います。
※WindowsユーザーなのでWindwosの話になります。

たまにTwitterで「便利なショートカットキー」がタイムラインに流れてくることがあります。
Ctrl+sで保存、Ctrl+cでコピー、Ctrl+vでペースト…
このあたりは有名所かなって思います。
ところでファンクションキーって使っていますか?
キーボードの一番上の段にある「F」から始まる1~12のキーです。
根が字書きなので、このファンクションキーにはとてもお世話になっています。
今回は私がよく使っているファンクションキーをご紹介します!
※ノートパソコンやパソコンの販売会社によってはファンクションキーの入力方法が少し異なる場合があります。

F2はリネーム
名前を変更したいファイルを選択後、F2を押すと名前を変更できます。
ちなみに、エクスプローラー上で名前を変更している場合、Tabキーを押すと次のファイルを自動で名前変更できます。
アプリなどによってはTabキーは「次の項目」を選択してしまうことがあるので、すべてに使えるわけではないのですが、エクスプローラー上であればTabキーとの組み合わせが便利です。

F5はリロード
「F5連打」なんて言葉を聞いたことがあります。それはつまり更新しまくっているわけです。
ローカルで作業していてブラウザ上に変更内容を反映させるときにF5をよく押します。
F5はただのリロードですが、Shift+F5でスーパーリロードができます。
通常サイトを見るときは、次のアクセス時に早く表示されるようサイトのデータを一時的にブラウザに保管されるのです(このデータをキャッシュといいます)。ただのリロードではこのデータをもう一度読み込んでしまい、更新内容が反映されないことがあるのです。
スーパーリロードは、このキャッシュを削除してサイトを読み直すので古いデータではなく最新を表示させることができます。
もし「更新したのに内容が変わってないな?」ということがあれば、スーパーリロードをお試しあれ。

F6はひらがな
普通に打っていればひらがなになるのであまり使わないですが、「表現としてカタカナにしてみたけどひらがなで良さそうだな」みたいな、変換途中でひらがな以外にしたあとひらがなに戻したいときはF6が便利です。あくまで入力確定前にF6するとひらがなに戻るよというものです。
紹介はしましたがそこまで使用頻度は高くないかも…?

F7は全角カタカナ
これは結構使います。打った文章すべてカタカナにしたいときや、変換でカタカナがなかなか出ないときなんかに便利です。
カタコトなセリフだとか描写だとかで、全部カタカナにしたい!というときはF7です。
一応、数字や子音(aiueo以外のアルファベット)、記号もF7を打つと全角になります。

F8は半角カタカナ
イイハナシダナー
というような、打った文章を全部半角カタカナにしたいときはF8で一発です。
F8を知ってからは、それまで半角カタカナどうやって打ってたっけな…と思い出せないくらいお世話になってます。
こちらも、数字や子音(aiueo以外のアルファベット)、記号もF8を打つと半角になります。

F9は全角アルファベット
Shiftと一緒にアルファベットキーを押せば大文字アルファベットが打てますよね。
じゃあ全角はどうする?その答えがF9です。
変換から探すより圧倒的楽。もともとは全角アルファベットをそんなに使っていなかったのですが、最近創作するにあたって自分の中で記述ルールを定めた結果、全角アルファベットや全角数字を使うようになりました。
アルファベットといってますが数字や記号も全角にできます。

F10は半角アルファベット
これが本当に便利。
「あ、間違えて全角のまま入力しちゃった」となってもF10を押せば一発で半角アルファベットになります。英単語とかで重宝しますね。
コードを打つときのような基本が半角アルファベットの状態であれば、そもそも入力を半角設定にすれば良いのですが、ちょっとした単語や文章で半角表記にしたいときに便利です。

F11は全画面表示
フォーカスがあたっているアプリが全画面になります。もう一度F11を押せば全体化する前のサイズに戻ります。
私は使う頻度はかなり少ないです。が、なんとなく紹介してみました。

他のファンクションキー
F1はアプリによって挙動が異なるので割愛しました。ブラウザ上でやったらヘルプページに飛ぶみたいです。VSCode上でやるとコマンドパレットになります。
F12はブラウザ上でやるとデベロッパーツールになります。デベロッパーツールはよくお世話になりますが、こちらの使い方はファンクションキーの紹介とは異なってしまうので割愛しました。

最後に
なんてことなく使っていたファンクションキーを、今日家族に頼まれパソコン操作してる中でさりげなく使ったら「なにそれ?何したの?」と聞かれました。
家族は最近の端末に疎いので気にしなかったのですが、自分の中ではみんな知ってるだろうなぁと思うことでも案外知らない人がいるかもしれない、と思いこの記事を書いてみました。
ショートカットキーしかりファンクションキーしかり、覚えて使い慣れるまで時間かかるかもしれませんが、慣れるととっても便利です!
私も知った当初はF6からF10まで欲しい変換が来るまで総当りしてました(笑)
便利!と思いましたら、ぜひぜひご活用ください♪
当サイトはお問い合わせページ以外すべて「てがろぐ」で管理しています。
てがろぐのスキンは自由に設定でき、自分好みやサイトに合わせたデザインにできるのは魅力のひとつ。
しかしてがろぐはcgiで作られており、htmlファイルと異なり簡単に確認するのが難しい…。
製作者様は「AN HTTPDがオススメ」とこちらでおっしゃられています。
実際に使ってみたらさっくり使えたので便利…ではあるのですが…
ちょっと私には使いにくい部分がありました。
  • Perlを導入しないといけないため、AN HTTPDだけで完結しない
  • 複数サイトでてがろぐを利用している場合、ドキュメントルートを都度変更しないといけない
  • 通常起動はdefault設定で、他の設定で開く場合はコマンドプロンプトから起動しないといけない

サイトごとドキュメントルートを設定したオプションデータを用意すればいいんだろうな、とは分かるのですがコマンドプロンプトから起動するのがちょっとメンドクサイ。
また所用で以前にXAMPPを落としていたので「やるならすでに持ってるXAMPPでやりたいんだ!」と欲望がありました。
ということで今回はXAMPPを使いローカルでてがろぐを利用する方法をご紹介します。

この記事で最終的にできるコト
ローカル環境でてがろぐを使える

今回の環境
  • Windows10
  • Google Chrome
  • XAMPP v3.3.0


今回のディレクトリ構成
C:\
└xampp
XAMPPのDLはこちらからどうぞ!
インストール時に指定しなければCドライブ直下にxamppの名前で配置されます。

D:\
サイト保管フォルダ
├サイトA(てがろぐ使用)
├サイトB(てがろぐ使用)
└サイトC
別のドライブにサイトデータを入れており、各サイトごとデータがフォルダに入っている状態です。
ドライブが同じでも大丈夫です。

XAMPPの設定
設定の前にXAMPPが正しく動作するか確認しておきましょう。
インストールしたらxamppフォルダの中にあるxampp-control.exeを起動します。
XAMPPはこの実行データを起動するので、デスクトップにショートカットをおいたりスタート画面やタスクバーにピン止めすると楽です。
XAMPPのコントロールパネルが表示されたらApacheのStartボタンを押してみましょう。
20230403185601-admin.png
これが
202304031856011-admin.png
こうなればOK!
これでローカル環境でサーバーが立っている状態です。
続けてApacheのAdminを押してみましょう。
ブラウザが開きます。
20230403185808-admin.png]
この画面が出ていたら正常に動作しています。
URLはhttp://localhost/dashboard/になってるかと思います。
無事に表示されたら、XAMPPの設定をしていきましょう。
ApacheのStopを押してサーバーを停止させておきます。

設定をしていくにあたりXAMPPを管理者以外で実行すると、閉じるときにエラーを吐かれることがあります。
エラー内容は「xampp-control.ini アクセスが拒否されました」というもので、コントロールの設定を管理者以外がいじれないような権限になっているようです。
管理者として実行すればいいだけの話なのですが、より快適な開発環境を目指し権限を設定し直します。
インストールしたxamppフォルダ内に「xampp-control.ini」があるので、右クリック→プロパティでフルコントロールを許可しておきましょう。
画像付きでやり方が知りたい方はこちらを参考にしているのでご覧くださいませ。

それでは次の項目から設定していきましょう!

.htaccessを無効化する
ファイル名をわざわざ index.cgi に変更しなくても、「tegalog.cgi」を省略して「/」で終わるURLでアクセスできるようにする方法を利用している人や、その他サイト内でアクセス周りを.htaccessで設定している人向けです。
XAMPPは.htaccessも対応している優れものなのですが、てがろぐ公式の方法で「tegalog.cgi」を省略するとローカルでてがろぐにログインできないことがあります。
.htaccessの内容をコメントアウトするやり方もありますが、確認のためにコメントアウトして、サイトにあげるときにもとに戻して…やはり手間ですね。コメントアウトしたままあげてしまう可能性も当然あります。
ということで.htaccessを使用しない設定をします。

C:\xampp\apache\conf内にhttpd.confというファイルを書き換えていきます。
何が起きても良いようにバックアップを取っておきましょう
httpd.confファイルを複製し、コピーした方を「httpd-original.conf」のように分かりやすく名前を変更しておきます。
ではhttpd.confの中身を書き換えていきます。
テキストエディタで開きCtrl+Fで「.htaccess」を検索します。
ファイル内に2箇所記述がありますが
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
#   AllowOverride FileInfo AuthConfig Limit
AllowOverride All

の項目の方です。簡単に言うと「.htaccess反映させるならAllだしさせないならNoneか、ディレクトリタイプ指定してね」です。
今回はすべての.htaccessを無効化したいと思うので
AllowOverride All
AllowOverride Noneに書き換えます。
細かい設定したい方はこちらが参考になるかと思います。

アクセス先を変える
httpd.confでドキュメントルートを変更するやり方も勿論ありますが、設定周りは極力いじりたくないので別の方法でやります。
C:\xampp\htdocs内にindex.phpがあります。
XAMPPの動作確認で開いたページがindex.phpなんです。…というのは正確ではありませんね。
テキストエディタで開いてみると分かるのですが、index.phpはローカルで開くディレクトリを設定しています。
<?php
   if (!empty($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'])) {
      $uri = 'https://';
   } else {
      $uri = 'http://';
   }
   $uri .= $_SERVER['HTTP_HOST'];
   header('Location: '.$uri.'/dashboard/');
   exit;
?>
Something is wrong with the XAMPP installation :-(

index.phpとおなじ階層にdashboardフォルダがありますが、それを開くよう設定されているのです。
サイトデータは別の場所にあるので、その場所を指定するための準備をします。ここではdashboardをsiteに書き換えておきましょう。
<?php
   if (!empty($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'])) {
      $uri = 'https://';
   } else {
      $uri = 'http://';
   }
   $uri .= $_SERVER['HTTP_HOST'];
   header('Location: '.$uri.'/site/');
   exit;
?>
Something is wrong with the XAMPP installation :-(
これでOKです。
この続きは次項目「シンボリックリンク」で行います。

シンボリックリンク
なんそれ?と思うでしょう。私も最初なんやそれと思いました。
IT用語辞典e-Wordsによると
シンボリックリンクとは、オペレーティングシステム(OS)のファイルシステムの機能の一つで、特定のファイルやディレクトリを指し示す別のファイルを作成し、それを通じて本体を参照できるようにする仕組み。
だそうです。これは要するにショートカットみたいなものです。
これを利用していきましょう。
シンボリックリンクの作成・削除はこちらのやり方でやっています。

dashboardではなくsiteを開くようにする
コマンドプロンプトを管理者で実行します。管理者として実行しないとシンボリックリンクが作れないので注意しましょう。
現在ルートが「C:\Windows\system32」となっているのでルートまで移動しておきます
cd /といれエンターを押すとルートが「C:\」へ移動したかと思います。
それではここでシンボリックリンクを作っていきます。
サイトが管理されているディレクトリパスが必要です。
今回は構成は
D:\
サイト保管フォルダ
├サイトa(てがろぐ使用)
├サイトb(てがろぐ使用)
└サイトc
なので「D:\サイト保管フォルダ」が必要なパスです。
シンボリックリンクの作り方は
mklink /D (シンボリックリンク名) (リンク先フォルダ)です。
これをあてはめると
mklink /D C:\xampp\htdocs\site D:\サイト保管フォルダとなります。
これでエンターを押すとC:\xampp\htdocs内に「site」というフォルダができているはずです。
追加されたシンボリックリンク
動作確認をしてみましょう。
XAMPPを起動しApacheでStartを押し、Adminを押します。
20230403205658-admin.png
このような画面が出ればOKです。
「D:\サイト保管フォルダ」内にあるものが列挙されているかと思います。
私はよりわかりやすいように、このサイト保管フォルダに簡単にindex.htmlを用意して
20230403210119-admin.png
と表示させています。
※この時点ではまだてがろぐは正常に動作しません。

tegalog.cgiのシバンを書き換える
tegalog.cgiの冒頭に
#! /usr/bin/env perlとありますよね。これがシバン(シェバン)です。
もちろんサーバーがこれで動くのであれば書き換えないに越したことはありません。
しかしローカルで作業するにはこのシバンでは動作できません。
このenvがperlのバージョンに合わせてパスを通してくれるそうなのですが、Windwosだとこのenvを作れそうにありません。
なので「サーバーのperlパス」を書くようにします。
レンタルサーバーによるのですが、幸い私が借りているサーバーはperlパスがある程度統一されていました。

CORESERVER(各種パスについて / てがろぐ設定方法):/usr/bin/perl
リトルサーバー(各プログラムのパス):/usr/bin/perl
WitchServer(CGIパス):/usr/bin/perl

XAMPPのperlへのパスもシンボリックリンクを利用しますが、サーバーやサイトごとにシンボリックリンクを何個も作るのはあんまり好きじゃなかったので、ひとつで済むように統一させました。
よってtegalog.cgiのシバンは
#! /usr/bin/perlに書き換えます。
※レンタルサーバーによります。ご自身の環境に合うように適宜変更してください。

Perlへのシンボリックリンクをつくる
それでは先程書き換えたシバンに合うようにシンボリックリンクを作ります。
今回書き換えたシバン(/usr/bin/perl)の場合、「C:\usr\bin\perl.exeを実行するよ」となればいいですね。
XAMPPのperl.exeはC:\xampp\perl\binにありますので、「C:\usr」と「C:\xampp\perl」でシンボリックリンクを作れば良さそうです。
ですので
mklink /D C:\usr C:\xampp\perlをコマンドプロンプトで打ちます。
これでようやくXAMPPを使ってローカル環境でてがろぐが確認できるのです。
おめでとう!!!
なお、Perlへのシンボリックリンク作成については「てがろぐをローカル設置しようとして詰まった箇所とその対応」を参考にしました。ありがとうございます。

おまけ:スマホでも確認したい!
ローカルでサーバーが立っているので、同一ネットワークであれば別の端末でも確認ができます。同一ネットワークというのは、同じルーターを使っているとか同じWifiを使っているとかそんな感じです。
XAMPPでサーバーを立て(ApacheのStartを押した状態で)サイトを開くと、http://localhost/から始まるURLになっています。
このlocalhostの部分にサーバーを立てた端末のIPアドレスを入れれば別の端末からでも確認ができます。
コマンドプロンプトで「ipconfig」と打つと
20230403220847-admin.png
こんな感じで情報が出てきます。
これの「IPv4アドレス」がlocalhostにあたります。
WSL(Windows Subsystem for Linux、WindowsでLinuxプログラムを使うためのサブシステム)を入れていると、画像の下のようにWSLのIPアドレスが表示されますが上の方のIPアドレスです。
ローカルのIPアドレスであれば大抵192.168から始まると思います。
IPアドレスが192.168.0.11だとしたら、スマホなど別の端末で見るときは「http://192.168.0.11/」から始まるURLでサイトを確認できます。
(例:http://localhost/site/個人サイト/tegalog.cgiを見たいのであればhttp://192.168.0.11/site/個人サイト/tegalog.cgiでアクセス可能)

最後に
XAMPPに入ってるPerlはStrawberry Perlの一部らしいですが、完全版を入れずともXAMPPの初期部分だけでてがろぐは動作します。
また記事冒頭リンクにあるとおり、てがろぐ作者にしし様がオススメしているやり方ですと「ActivePerl」のインストールとなっていますが違うPerlでも特に問題ないかと思います。
今回は「意地でもXAMPPを使ってローカルでてがろぐやるんだ!」の意志で設定しました。
AN HTTPDはシバンに関係なく動作するので、シバンを書き換えたくない場合はAN HTTPDをオススメします。
「XAMPP持ってるけどAN HTTPD使うぞ」という場合は、Perlを別途インストールせずともAN HTTPDのPerlパスをXAMPPのPerlのある場所に設定すれば動作します。お試しあれ!

関連記事
ローカルでもドメイン使用!?XAMPPのVirtualHostとはっ

参考リンクまとめ
※敬称略
にししふぁくとりー:AN HTTPDはWayback Machineから今でもダウンロードはできる
XAMPP
Notes de Design:xampp-control.iniにアクセス拒否された!管理者権限の付与ですぐ解決
てがろぐセットアップ:ファイル名をわざわざ index.cgi に変更しなくても、「tegalog.cgi」を省略して「/」で終わるURLでアクセスできるようにする方法
JavaDrive:AllowOverrideディレクティブ:.htaccessを使った設定の上書きを許可する
IT用語辞典e-Words:シンボリックリンク
iPentec:シンボリックリンクの作成と削除 (Windows Tips)
CORESERVER:各種パスについて
Value Domain:コアサーバー初心者の為のCGI設置講座
リトルサーバー:Q.各プログラムのパスを教えてください
WitchServer:プラン詳細
日々放置プレイ:てがろぐをローカル設置しようとして詰まった箇所とその対応
当記事はQiita版があります。
Qiita版はこちら
今回はGitHubActionsの方に絞ってご紹介いたします。

サイトの更新をもっと楽にしたい!
そんな自堕落を突き詰めた結果、GitHubActionsを利用することでボタンポチッで更新ができると知りました。
今回はその備忘録を残します。

この記事で最終的にできるコト
  • サーバー上にあるファイルとの同期(削除されたファイルも含め)
  • 特定のファイルやディレクトリをあげないようにする
    • 下書きなどGitHubで管理したいけどサーバーには上げたくない場合


今回の環境
  • Windows10
  • GitHub
  • Sourcetree
  • Value DomainのCORESERVER
  • リトルサーバー

当サイトはWitchServerを使用していますが、WitchServerでのやり方は現在模索中なのでお待ちくださいませ…。 こちらに投稿しました!→GitHubActionsでサイト自動更新【WitchServer編】

Actions secrets
暗号化の設定をしておきましょう。
設定はリポジトリのSettings→左カラムSecurity項目のSecrets and variables→Actionsにあります。
「New repository secret」という緑のボタンがあるので、そこから設定していきます。
ボタンを押すと「Name」「Secret」の記入項目が出てきます。

①FTPサーバー
Nameに「FTP_SERVER」、SecretにFTPサーバー名を入れ「Add secret」で追加します。
FTPサーバー名は契約しているサーバー毎に異なります。
CORESERVERでは「ホスト」、リトルサーバーでは「FTPサーバー」にあたります。

②FTPユーザー名
Nameに「FTP_USERNAME」、SecretにFTPアカウント名を入れ追加します。
CORESERVERでは「アカウント」、リトルサーバーでは「FTPアカウント」にあたります。

③FTPパスワード
Nameに「FTP_PASSWORD」、SecretにFTPアカウントに紐づいているパスワードを入れ追加します。
CORESERVERでは「パスワード」、リトルサーバーでは「FTPアカウント」にあたります。

CORESERVERでは新コントロールパネルのサイト設定→FTP設定から上記設定が見れます。
20230402232513-admin.png

リトルサーバーではコントロールパネルのパネルホームでFTPサーバーが見れます。
202304022325131-admin.png
リトルサーバーでのFTPアカウントやFTPパスワードは契約時に設定したものです。

また、サーバー内のディレクトリもSecretにしたい場合は「SERVER_DIRECTORY」などと設定しても良いでしょう。


ymlを書くぞ!
いよいよymlを作ります。
リポジトリのActionsで「set up a workflow yourself」を選択。
下の方にスターターセットみたいな感じでいろいろありますが、今回は直接打って設定するのでスルーします。
「set up a workflow yourself」は一番上の「Get started with GitHub Actions」の下2行目あたりにあります。

ymlの名前は何でもいいです。今回はデフォルトの「main.yml」のままにします。
まず全文お見せします。
on:
  push:
    branches:           
      - main   
name: FTP Deploy and Push
jobs:
  web-deploy:
      name: Deploy
      runs-on: ubuntu-latest
      steps:
      - name: Get latest code
        uses: actions/checkout@v2

      - name: Sync files
        uses: SamKirkland/FTP-Deploy-Action@4.3.2
        with:                                       
          server: ${{ secrets.FTP_SERVER }}     
          username: ${{ secrets.FTP_USERNAME }}
          password: ${{ secrets.FTP_PASSWORD }}
          local-dir: ローカルディレクトリ
          server-dir: サーバーディレクトリ
          exclude: |
            **/.git*
            **/.git*/**
            **/node_modules/**
            **/test/**
            **/test-*/**
            **/test-*.html


中身を見ていきましょう。
on:
  push:
    branches:           
      - main   

pushしたらmainブランチにActionsを走らせます。
別のブランチでActionsを走らせたいときはmainを走らせたいブランチ名にしましょう。

- name: Sync files
  uses: SamKirkland/FTP-Deploy-Action@4.3.2

FTP Deploy を使用します。
私が自分の環境に実装したときは4.3.2でしたが、数週間前に最新バージョン4.3.4が出ています。
そこまで大きく内容は変わらないと思いますが、最新バージョンを使う際は上記リンクから内容を確認して実装してください。
過去バージョン(2.*.*や3.*.*)と現在は結構書き方が変わっているので、何らかの事情で過去バージョンの使用を検討している方は要注意です。

with:                                       
    server: ${{ secrets.FTP_SERVER }}     
    username: ${{ secrets.FTP_USERNAME }}
    password: ${{ secrets.FTP_PASSWORD }}
    local-dir: ローカルディレクトリ
    server-dir: サーバーディレクトリ

Secretで設定したものがここにはいります。FTP_SERVERなどの部分は設定したNameと一致しなければ正常に動作しません。
「secretsに設定したFTP_SERVERを使います」の明示です。

local-dirは設定しない場合はroot以下が対象になります。
私の場合、
root/
├.git
├.github
└main/inde.htmlなど内容物
とサイトにあげたい内容をmainフォルダに入れているので
local-dir: ./main/と記入しています。

サーバーディレクトリはSecretで設定している場合は
server-dir: ${{ secrets.SERVER_DIRECTORY }}になるかと思います。
契約しているサーバーによって変わりますが、例えばexmaple.comというドメインであれば
CORESERVERなら「/public_html/exmaple.com/」
リトルサーバーなら「/pub/exmaple.com/」が入ります。

exclude: |
    **/.git*
    **/.git*/**
    **/node_modules/**
    **/test/**
    **/test-*/**
    **/test-*.html

これは「GitHubで管理したいけどサーバーにはまだあげたくない!」というファイルやディレクトリがある場合に記述します。特にそういったものがなければ、この項目はまるっと消して大丈夫です。
「**/.git*」「**/.git*/**」は「.github」ディレクトリや「.gitignore」などのことです。
「**/node_modules/**」は個人サイトで使用することはほとんどないんじゃないかなと思うのですが、Node.jsなどのサーバーサイドのプログラムモジュールのことだと思います。
先程も言った通り「あげたくないものはない」のであれば「exclude」以下はすべて消していいのですが、サーバーにあげないファイルを設定する場合は「**/.git*」「**/.git*/**」「**/node_modules/**」は必須です
むしろこれがないと正常に動作しません。
こちらのIssuesにその旨がかいてあったのと、普通にドキュメントにも書いてありました。
私はこれに気付かず苦戦を…ドキュメント、ダイジ

「**/test/**」「**/test-*/**」「**/test-*.html」が本命のサーバーにあげないファイルです。
ワイルドカードを使っていますが直接の指定も可能です。
「**/test/**」……すべてのtestフォルダ以下にあるものすべて
「**/test-*/**」……すべてのtest-から始まるフォルダ以下にあるものすべて
「**/test-*.html」……すべてのtest-から始まるhtmlファイル
という感じです。
私はよく「編集途中だけどGitHubにはあげたい!でも編集途中だからサーバーにはあげたくない!」ということがよくあるので、そういうときに重宝しています。
サンプルとしてそれぞれ「test」としていますが「sample」でも「sitagaki」でも何でも大丈夫です。
サーバーにあげたいファイルやフォルダとは異なる名前であればOK!

ymlを書いたらコミットしましょう。
ymlはGitHub上で作成したのでローカルではpullを忘れずに。
私はSoucetree愛用者なのでSoucetreeであれこれやってます。

注意
GitHub上でymlを作った場合、ymlの中身をローカルで編集するとエラーを吐かれます(ブチギレられます)
なのでymlを編集するときはGitHub上で行いコミットしたらpullするようにしましょう。
最初からローカルで作る場合は試していないのでどうなるかわからないです。いつか試してみます、多分。
【追記】ローカルで作ったり編集したりしたymlをpushするにはGitHubで認証キーを作成しSoucetreeで設定しないといけませんでした。
ローカルで作業したい方はこちらご覧くださいませ(別の方が執筆した内容です)

おまけ
Actionsが正常に動作したかも気軽に確認したいですよね。
GitHubへいちいち見に行くのも面倒だし、サイトをひたすらリロードもちょっと…って感じ。
なので「Actionsの結果を通知してくれる」便利なActionsを追加します。
SlackやLINEもあるみたいですが、今回はDiscordへ通知をくれるActions Status Discordを導入します。

①通知をおくるDiscordサーバーのサーバー設定から連携サービス→ウェブフックを確認を選択。
「新しいウェブフック」ボタンを押すと下にウェブフックが追加されます。
追加されたウェブフックを選択し、名前を好きに決めチャンネルを通知を送りたいチャンネルに設定します。
そして「ウェブフックURLをコピー」を押してコピーしましょう。

②Actions secretsにName「DISCORD_WEBHOOK」でsecretsに先ほどコピーしたURLを貼り追加します。

③先程のymlに追記します。
- name: Push Call Discord
  uses: sarisia/actions-status-discord@v1
  if: always()
  env:
    DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
  with:
    title: "タイトル"
    description: "共通説明"

with以下はDiscordに送る内容を好きに設定できます。
ドキュメントを見て欲しいものを入れると良いでしょう。

最終的なymlはこうなりました。
on:
  push:
    branches:           
      - main   
name: FTP Deploy and Push Discord
jobs:
  web-deploy:
      name: Deploy
      runs-on: ubuntu-latest
      steps:
      - name: Get latest code
        uses: actions/checkout@v2

      - name: Sync files
        uses: SamKirkland/FTP-Deploy-Action@4.3.2
        with:                                       
          server: ${{ secrets.FTP_SERVER }}     
          username: ${{ secrets.FTP_USERNAME }}
          password: ${{ secrets.FTP_PASSWORD }}
          local-dir: ローカルディレクトリ
          server-dir: サーバーディレクトリ
             
      - name: Push Call Discord
        uses: sarisia/actions-status-discord@v1
        if: always()
        env:
          DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
        with:
         title: "タイトル"
         description: "簡易説明"


最後に
今回はGitHubを使用しましたが、BitbucketでもpipelineというActionsと同じような機能があるのでそちらでもできるみたいです。
また今回はFTPだけなので、FTPSやSFTPはまたちょっと記述が変わってきます。
ひとまずFTPでデプロイする場合はこちらのGitHubActionsを参考にしてみてください。

関連記事
GitHubActionsでサイト自動更新【WitchServer編】

サイト紹介

当サイトをご覧頂きありがとうございます!
こちらは「畑違いの元プログラマが個人サイトをやっていて得た知見・技術」などを、備忘録兼紹介しているサイトです。
畑違いの元プログラマ?
元ゲームプログラマです。C、C++、C#といった言語を扱ってました。
仕事でObjective-Cも触りましたが今はもううろおぼえ…。
ただブランクあるので「ゲーム作って!」と言われたら多分すぐには作れないですね。もはや過去の技術……。
そんなわけで、サイト作りで使うhtml、css、JavaScriptなどの言語はちんぷんかんぷんの状態から始まりました。
元とはいえプログラマだったおかげで、プログラミングへの忌避感は特にありません。新しいもの大好き。
どんな内容のサイト?
テーマは「過去の私に教えたい!」「同じ問題で詰まってる人に届けたい!」です。
傾向的にはサイト作りで使ったツールの「紹介」「使い方」「躓いたところと解決方法」などを載せていこうと思います。ですので、エンジニアであれば見たことがあるかもしれない「Q」から始まる某知識共有サービスをイメージしてます。

また、サイト名「てくてく」は「テクノロジーとテクニック」からもじりつつ、「一歩一歩てくてくと学んでいこう」という思いが込められています。

最後に
当サイトも個人サイトのひとつとしてまったり運営する予定です。
更新があったりなかったりまばらになると思いますが、どうぞよろしくお願い致します!

管理人:とーれ
X:https://twitter.com/techtech_site

DASHBOARD

つぶやき

アカウント作成しました!
Twitter(現X)

全文検索

カレンダー

日付一覧を表示
2023年9月
12
3456789
10111213141516
17181920212223
24252627282930

Thanks !

Link

Contact

目次