20200326のHTMLに関する記事は9件です。

最強のしりとりAIを作ってみた

しりとりができるAIを作ってみた。

前回はGASを使ってLINE BOTを作りましたが、
今回はWebでJavascriptを使って作ってみます。

使ったAPI

gooラボ ひらがな化API
ウィキペディア MediaWikiAPI

あとjQueryとFont Awesomeのアイコンフォントを使います。
使用したアイコンはこれこれです

コード

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>しりとり AI</title>
    <link rel="stylesheet" href="chat_UI.css">
    <script src="https://kit.fontawesome.com/xxxxx.js" crossorigin="anonymous"></script>
    <link rel="icon" href="./icons/favicon.ico">
</head>
<body>
    <script src="./jquery-3.4.1.min.js"></script>
    <div id="chat-box">
        <div class="kaiwa">
            <!--左からの吹き出し-->
                <figure class="kaiwa-img-left">
                    <img src="./icons/Wikipedia-logo-v2-ja.png" alt="no-img2">
                    <figcaption class="kaiwa-img-description">
                        しりとり AI
                    </figcaption>
                </figure>
                <div class="kaiwa-text-right">
                    <p class="kaiwa-text">
                        こんにちは。僕はしりとりAIだよ。<br>
                        Wikipediaから集めたデータを使ってしりとりができるよ。<br>
                        じゃあ、始めるよ~
                    </p>
                </div>
        </div>
        <!--左からの吹き出し 終了-->

            <div class="kaiwa">
                <figure class="kaiwa-img-left">
                    <img src="./icons/Wikipedia-logo-v2-ja.png" alt="no-img2">
                    <figcaption class="kaiwa-img-description">
                        しりとり AI
                    </figcaption>
                </figure>
                <div class="kaiwa-text-right">
                    <p class="kaiwa-text">
                        「しりとり」
                    </p>
                </div>
            </div>
    </div>
    <div id="form">
        <textarea id="text" cols="30" rows="3" placeholder="「り」から始まる言葉"></textarea>
        <div id="buttons">
            <button id="submit"><i class="far fa-paper-plane"></i> <span id="submit_text">送信</span></button>
            <button id="btn"><i class="fas fa-microphone"></i> <span id="btn_text">マイク</span></button>

        </div>
    </div>

    <script src="./siritori.js"></script>
</body>
</html>

次に見た目を作るCSSです。

chat_UI.css
/*——————–
 吹き出しを作る
——————–*/

/* 全体のスタイル */

.kaiwa {
  margin-bottom: 35px;
}

/* 左画像 */

.kaiwa-img-left {
  margin: 0;
  float: left;
  width: 60px;
  height: 60px;
  margin-right: -70px;
}

/* 右画像 */

.kaiwa-img-right {
  margin: 0;
  margin-right: 10px;
  float: right;
  width: 60px;
  height: 60px;
  margin-left: -70px;
}

.kaiwa figure img {
  width: 100%;
  height: 100%;
  border: 1px solid #aaa;
  border-radius: 50%;
  margin: 0;
}

/* 画像の下のテキスト */

.kaiwa-img-description {
  padding: 20px 0 0;
  font-size: 12px;
  text-align: center;
  position: relative;
  bottom: 15px;
}

/* 左からの吹き出しテキスト */

.kaiwa-text-right {
  position: relative;
  margin-left: 80px;
  padding: 10px;
  border-radius: 10px;
  background: #eee;
  margin-right: 20%;
  float: left;
}

/* 右からの吹き出しテキスト */

.kaiwa-text-left {
  position: relative;
  margin-right: 80px;
  padding: 10px;
  border-radius: 10px;
  background-color: #9cd6e7;
  margin-left: 20%;
  float: right;
}

p.kaiwa-text {
  margin: 0 0 20px;
}

p.kaiwa-text:last-child {
  margin-bottom: 0;
}

/* 左の三角形を作る */

.kaiwa-text-right:before {
  position: absolute;
  content: '';
  border: 10px solid transparent;
  top: 15px;
  left: -20px;
}

.kaiwa-text-right:after {
  position: absolute;
  content: '';
  border: 10px solid transparent;
  border-right: 10px solid #eee;
  top: 15px;
  left: -19px;
}

/* 右の三角形を作る */

.kaiwa-text-left:before {
  position: absolute;
  content: '';
  border: 10px solid transparent;
  top: 15px;
  right: -20px;
}

.kaiwa-text-left:after {
  position: absolute;
  content: '';
  border: 10px solid transparent;
  border-left: 10px solid #9cd6e7;
  top: 15px;
  right: -19px;
}

/* 回り込み解除 */

.kaiwa:after, .kaiwa:before {
  clear: both;
  content: "";
  display: block;
}

#text {
  resize: none;
  float: left;
  margin-right: 10px;
}

#chat-box {
  height: 500px;
  overflow-y: scroll;
}

#btn, #submit {
  margin-left: 10px;
  margin-bottom: 50px;
}

#btn, #submit {
  border-radius: 25px;
  position: relative;
  display: inline-block;
  font-weight: bold;
  padding: 0.25em 0.5em;
  text-decoration: none;
  color: #FFF;
  background: #00bcd4;
  transition: .4s;
  border-bottom: solid 4px #627295;
}

#submit:hover {
  background: #00ff00;
}

#btn:hover {
  background: #ff0000;
}

#btn:active {
  /*ボタンを押したとき*/
  -webkit-transform: translateY(4px);
  transform: translateY(4px);
  /*下に動く*/
  border-bottom: none;
  /*線を消す*/
}

#submit:active {
  /*ボタンを押したとき*/
  -webkit-transform: translateY(4px);
  transform: translateY(4px);
  /*下に動く*/
  border-bottom: none;
  /*線を消す*/
}

::placeholder {
  color: #ff0000;
  opacity: 0.5;
  font-size: 18px;
}

index.htmlの8行目の

<script src="https://kit.fontawesome.com/xxxxx.js" crossorigin="anonymous"</script>

の「xxxxx.js」の部分は自分で変更してください。

ここまで書くと、このような見た目になると思います。プレビュー

次はしりとりの処理のJavascriptのコードです。

siritori.js
var msg = new SpeechSynthesisUtterance();
//msg.lang = 'ja-JP'; //言語
var words = [];
var Word_history = [];
var cpu_word = "";
var next_word = "";
var Iswork = false;
//音声認識の準備
const obj = document.getElementById("chat-box");
SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
const speech = new SpeechRecognition();
if ('SpeechRecognition' in window) {
    // ユーザのブラウザは音声合成に対応しています。
} else {
    $("#btn").hide();
}
speech.lang = "ja-JP";
speech.continuous = true;
//使用する変数を用意
$("#submit").click(function () {
    $("#submit").css('background-color', '#999999');
    $("#btn").css('background-color', '#999999');
    var text = $("#text").val();
    if (text == "") {
        $("#btn").prop("disabled", false);
        $("#submit").prop("disabled", false);
        $("#btn_text").text("マイク");
        $("#submit_text").text("送信");
        $("#btn").css('background-color', '#00bcd4');
        $("#submit").css('background-color', '#00bcd4');
        return; //何もないなら関数を終了させる
    }
    $("#btn").prop("disabled", true);
    $("#btn_text").text("処理中");
    $("#submit").prop("disabled", true);
    $("#submit_text").text("処理中");
    console.log("リザルト")
    console.log(text);//textが結果
    //ここから返答処理
    $("#chat-box").html($("#chat-box").html() + "<div class=\"kaiwa\"><!–右からの吹き出し–><figure class=\"kaiwa-img-right\"><img src=\"./icons/human_icon.png\" alt=\"no-img2\"><figcaption class=\"kaiwa-img-description\">あなた</figcaption></figure><div class=\"kaiwa-text-left\"><p class=\"kaiwa-text\">「" + text + "」</p></div></div><!–右からの吹き出し 終了–>");
    obj.scrollTop = obj.scrollHeight;
    //処理が終わったら考え中の文字を削除し、結果を入れる
    if (next_word != str_chenge(text, 1)[0]) {
        say("" + next_word + "」から言葉を始めてね!", $("#chat-box"));
        obj.scrollTop = obj.scrollHeight;
        $("#text").val("");
        $("#btn").prop("disabled", false);
        $("#submit").prop("disabled", false);
        $("#btn_text").text("マイク");
        $("#submit_text").text("送信");
        $("#btn").css('background-color', '#00bcd4');
        $("#submit").css('background-color', '#00bcd4');
        return;
    } else if (Word_history.indexOf(text) != -1) {
        say("" + text + "」は、もう使われた言葉だよ!", $("#chat-box"));
        obj.scrollTop = obj.scrollHeight;
        $("#text").val("");
        $("#btn").prop("disabled", false);
        $("#submit").prop("disabled", false);
        $("#btn_text").text("マイク");
        $("#submit_text").text("送信");
        $("#btn").css('background-color', '#00bcd4');
        $("#submit").css('background-color', '#00bcd4');
        return;
    } else {
        Word_history.push(text);
        siritori(text).then(function (value) {
            // 非同期処理成功
            console.log(value);
            $("#text").attr("placeholder", "" + str_chenge(value, -1)[0] + "」から始まる言葉");
            next_word = str_chenge(value, -1)[0]
            say("" + value + "", $("#chat-box"))
            Word_history.push(value);
            obj.scrollTop = obj.scrollHeight;
            msg.text = value;
            speechSynthesis.speak(msg);
            console.log("処理終了");
            $("#text").val("");
            $("#submit").prop("disabled", false);
            $("#btn").prop("disabled", false);
            $("#btn_text").text("マイク");
            $("#submit_text").text("送信");
            $("#btn").css('background-color', '#00bcd4');
            $("#submit").css('background-color', '#00bcd4');
        }).catch(function (error) {
            // 非同期処理失敗。呼ばれない
            console.log(error);
            say("エラーが起きました", $("#chat-box"))
            $("#text").val("");
            $("#btn").prop("disabled", false);
            $("#submit").prop("disabled", false);
            $("#btn_text").text("マイク");
            $("#submit_text").text("送信");
            $("#btn").css('background-color', '#00bcd4');
            $("#submit").css('background-color', '#00bcd4');
        });
    }
})
$("#btn").click(function () {
    // 音声認識をスタート
    if (!Iswork) {
        Iswork = true;
        $("#btn").prop("disabled", true);
        $("#btn_text").text("マイクで録音中");
        $("#btn").css('background-color', '#ff0000');
        $("#submit").prop("disabled", true);
        speech.start();
    } else { return; }
});
speech.onnomatch = function () {
    console.log("認識できませんでした");
    say("認識できませんでした", $("#chat-box"))
    $("#btn").prop("disabled", false);
    $("#btn_text").text("マイク");
    $("#submit").prop("disabled", false);
    $("#submit_text").text("送信");
    $("#btn").css('background-color', '#00bcd4');
    $("#submit").css('background-color', '#00bcd4');
    Iswork = false;
};
speech.onerror = function () {
    console.log("認識できませんでした");
    say("認識できませんでした", $("#chat-box"))
    $("#btn").prop("disabled", false);
    $("#btn_text").text("マイク");
    $("#submit").prop("disabled", false);
    $("#submit_text").text("送信");
    $("#btn").css('background-color', '#00bcd4');
    $("#submit").css('background-color', '#00bcd4');
    Iswork = false;
};
//音声自動文字起こし機能
speech.onresult = function (e) {
    $("#btn_text").text("処理中");
    $("#submit").prop("disabled", true);
    $("#submit_text").text("処理中");
    $("#submit").css('background-color', '#999999');
    $("#btn").css('background-color', '#999999');
    console.log("リザルト")
    speech.stop();
    if (e.results[0].isFinal) {
        console.log("聞き取り成功!")
        var autotext = e.results[0][0].transcript
        console.log(e);
        console.log(autotext);//autotextが結果
        //ここから返答処理
        $("#chat-box").html($("#chat-box").html() + "<div class=\"kaiwa\"><!–右からの吹き出し–><figure class=\"kaiwa-img-right\"><img src=\"./icons/human_icon.png\" alt=\"no-img2\"><figcaption class=\"kaiwa-img-description\">あなた</figcaption></figure><div class=\"kaiwa-text-left\"><p class=\"kaiwa-text\">「" + autotext + "」</p></div></div><!–右からの吹き出し 終了–>");
        obj.scrollTop = obj.scrollHeight;
        //処理が終わったら考え中の文字を削除し、結果を入れる
        if (next_word != str_chenge(autotext, 1)[0]) {
            say("" + next_word + "」から言葉を始めてね!", $("#chat-box"));
            obj.scrollTop = obj.scrollHeight;
            $("#text").val("");
            $("#btn").prop("disabled", false);
            $("#submit").prop("disabled", false);
            $("#btn_text").text("マイク");
            $("#submit_text").text("送信");
            $("#btn").css('background-color', '#00bcd4');
            $("#submit").css('background-color', '#00bcd4');
            return;
        } else if (Word_history.indexOf(autotext) != -1) {
            say("" + autotext + "」は、もう使われた言葉だよ!", $("#chat-box"));
            obj.scrollTop = obj.scrollHeight;
            $("#text").val("");
            $("#btn").prop("disabled", false);
            $("#submit").prop("disabled", false);
            $("#btn_text").text("マイク");
            $("#submit_text").text("送信");
            $("#btn").css('background-color', '#00bcd4');
            $("#submit").css('background-color', '#00bcd4');
            return;
        } else {
            Word_history.push(autotext);
            siritori(autotext).then(function (value) {
                // 非同期処理成功
                console.log(value);
                $("#text").attr("placeholder", "" + str_chenge(value, -1)[0] + "」から始まる言葉");
                next_word = str_chenge(value, -1)[0]
                say("" + value + "", $("#chat-box"));
                Word_history.push(value);
                obj.scrollTop = obj.scrollHeight;
                msg.text = value; speechSynthesis.speak(msg);
                console.log("処理終了")
                $("#btn").prop("disabled", false);
                $("#btn").css('background-color', '#00bcd4');
                $("#submit").css('background-color', '#00bcd4');
                $("#btn_text").text("マイク");
                $("#submit").prop("disabled", false);
                $("#submi_text").text("送信");
                Iswork = false;
            }).catch(function (error) {
                // 非同期処理失敗。呼ばれない
                console.log(error);
                $("#btn").prop("disabled", false);
                $("#btn").css('background-color', '#00bcd4');
                $("#submit").css('background-color', '#00bcd4');
                $("#btn_text").text("マイク");
                $("#submit").prop("disabled", false);
                $("#submit_text").text("送信");
                Iswork = false;
            });
        }
    }
}
function siritori(user_msg) {
    return new Promise(function (resolve, reject) {
        words = [];
        var chenges = str_chenge(user_msg, -1)
        var taskA = new Promise(function (resolve, reject) {
            WikipediaAPI(chenges[0], resolve);
        });
        var taskB = new Promise(function (resolve, reject) {
            WikipediaAPI(chenges[1], resolve);
        });
        Promise.all([taskA, taskB]).then(function () {
            console.log(words);
            cpu_word = words[Math.floor(Math.random() * words.length)]
            resolve(cpu_word);
        })
    });
}
function WikipediaAPI(query, end) {
    var NG_word = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
        , "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
        , "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
        , "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "綿", "", "", ""
        , "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""];
    //API呼び出し
    console.log(query)
    $.ajax({
        type: "GET",
        timeout: 10000,
        dataType: "jsonp",
        url: "https://ja.wikipedia.org/w/api.php?format=json&action=query&list=prefixsearch&pssearch=" + query + "&pslimit=200&psnamespace=0",
        async: false,
        success: function (json) {
            console.log(json)
            json.query.prefixsearch.forEach(function (value) {
                if (value.title != query) {
                    var word = value.title;
                    word = word.replace(/ *\([^)]*\) */g, "");
                    if (NG_word.indexOf(word.slice(-1)) == -1 && Word_history.indexOf(word) == -1) {
                        words.push(word);
                    }
                }
            });
            end();
        }
    });

}
function str_chenge(str, ran) {
    var range = ran
    if (range == 1) {
        range = [0, 1]
    } else {
        range = [-1, undefined]
    }
    const hiragana = ["", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "",
        "", "", "",
        "", "", "", "", "",
        "",
        "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
    ]
    const katakana = ["", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "",
        "", "", "",
        "", "", "", "", "",
        "",
        "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",
        "", "", "", "", "",]
    var r = [];
    var func_str = str;
    if (func_str.slice(range[0], range[1]) == "" || func_str.slice(range[0], range[1]) == "-" || func_str.slice(range[0], range[1]) == "!" || func_str.slice(range[0], range[1]) == "?" || func_str.slice(range[0], range[1]) == "" || func_str.slice(range[0], range[1]) == "") {
        func_str = func_str.slice(-2);
        func_str = func_str.slice(0, 1);
    }
    if (hiragana.indexOf(func_str.slice(range[0], range[1])) != -1) {//ひらがな
        r.push(func_str.slice(range[0], range[1]));
        r.push(katakana[hiragana.indexOf(func_str.slice(range[0], range[1]))]);
        console.log(r)
    } else if (katakana.indexOf(str.slice(range[0], range[1])) != -1) {//カタカナ
        r.push(hiragana[katakana.indexOf(func_str.slice(range[0], range[1]))]);
        r.push(func_str.slice(range[0], range[1]));
        console.log(r)
    } else {//漢字
        $.ajax({
            type: 'POST',
            timeout: 10000,
            url: "https://labs.goo.ne.jp/api/hiragana",
            async: false,
            'headers': {
                'Content-Type': "application/json",
            },
            data: JSON.stringify({
                'app_id': '自分のapp id',
                'sentence': func_str,
                'output_type': 'hiragana'
            }),
        }).done(function (data) {
            func_str = data.converted;
            if (func_str.slice(range[0], range[1]) == "") {
                func_str = func_str.slice(-2);
                func_str = func_str.slice(0, 1);
            } else {
                func_str = func_str.slice(range[0], range[1]);
            }
            r.push(func_str.slice(range[0], range[1]));
            r.push(katakana[hiragana.indexOf(func_str.slice(range[0], range[1]))]);
            console.log(r)
        });
    }
    switch (r[0]) {//小文字変換 ひらがな
        case "":
            r[0] = "";
            break;
        case "":
            r[0] = "";
            break;
        case "":
            r[0] = "";
            break;
        case "":
            r[0] = "";
            break;
        case "":
            r[0] = "";
            break;
        case "":
            r[0] = "";
            break;
        case "":
            r[0] = "";
            break;
        case "":
            r[0] = "";
            break;
        case "":
            r[0] = "";
            break;
        case "":
            r[0] = "";
            break;
        default:
            break;
    }
    switch (r[1]) {//小文字変換 カタカナ
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        case "":
            r[1] = "";
            break;
        default:
            break;
    }
    console.log(r);
    return r;
}
function say(text, element) {
    element.html(element.html() + "<div class=\"kaiwa\"><!-左からの吹き出し-><figure class=\"kaiwa-img-left\"><img src=\"./icons/Wikipedia-logo-v2-ja.png\" alt=\"no-img2\"><figcaption class=\"kaiwa-img-description\">しりとり AI</figcaption></figure><div class=\"kaiwa-text-right\"><p class=\"kaiwa-text\">" + text + "</p></div></div><!-左からの吹き出し 終了->")
}

とても長くなりました!

解説

このしりとりAIはなんと音声認識ができます!
しかし、SpeechRecognitionはまだブラウザが完全に対応してないのでバグが多いです。
(Windows版Chrome 80.0.3987.149 では結構しっかり動いた)
なのでtextareaから入力することをお勧めします。

siritori.jsではtextareaまたは音声認識で入力が来たら、まず前の言葉の最後の文字と頭文字が同じかチェックし、そのあとその言葉が今までに出たかをチェックします。

if (next_word != str_chenge(text, 1)[0]) {
//      ・・・略・・・
} else if (Word_history.indexOf(text) != -1) {
//      ・・・略・・・
}

その二つの条件をクリアしたら
関数siritori()を呼び、その中でWikipediaのAPIからしりとりの条件にある言葉を取得して返答しています。
関数WikipediaAPI()の中の配列NG_wordには「ん」で読み仮名が終わる漢字など返答の候補に入れる際、除外してほしい文字が入っています。
関数str_chengeは言葉をひらがなや、カタカナに変換し、最後や最初の一文字を返します。
「ー」や「!」などが最後の一文字の場合はその一つ前の文字を、
「ぁ」や「ゃ」などの小さい文字は「あ」や「や」に変換してくれます。

ひらがな化APIの部分にはgooラボAPI利用登録からgithubで登録してappidを取得して、str_chenge()のapp_idを書き換えてください。

function str_chenge(str, ran) {
    //  省略
     else {//漢字
        $.ajax({
            type: 'POST',
            timeout: 10000,
            url: "https://labs.goo.ne.jp/api/hiragana",
            async: false,
            'headers': {
                'Content-Type': "application/json",
            },
            data: JSON.stringify({
                'app_id': 'xxxxxxxxxxxxxx',// <=ここを書き換える
                'sentence': func_str,
                'output_type': 'hiragana'
            }),
        })
//   省略

こんなコードを書くとWikipediaの頭脳を持ったしりとりAIが完成します。

なんと!このAIは最後の文字を「ん」にしても言葉を返してきます!

遊んでみてください!
しりとり AI
GitHub

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPでデータベースに使ってみるための備忘録

はじめに

LAMP環境を整えてPHP使っておきながらPHP内でのデータベースの使い方がわからなかったので、忘れないようにまとめておきます。

簡単なスタッフの追加ページぽい何かとスタッフ一覧ページぽいものを作りながら簡単にまとめておきます。

準備

phpMyAdminを使ってデータベースに簡単なスタッフ管理を想定したテーブルを作ります。
カラムは3つで「code,name.password」のカラムを作ります。このうちcodeを主キーにします。
データの方などは以下の画像を参照してください
Screenshot from 2020-03-26 10-00-20.png

作ってみる

スタッフ追加ページ

まずはスタッフ追加ページを作ります。
スタッフ名とパスワード・確認用パスワードを入力する欄をHTMLで用意します。

staff_add.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    スタッフ追加<br/>
    <br/>
    <form method="post" action="add_confirm.php">
        スタッフ名を入力してください<br/>
        <input type="text" name="name" style="width:200px"><br/>
        パスワードを入力してください<br/>
        <input type="password" name="pass" style="width:100px"><br/>
        パスワードをもう一度入力してください<br/>
        <input type="password" name="pass2" style="width:100px"><br/>
        <br/>
        <input type="submit" value="登録">
    </form>
</body>.
</html>

Screenshot from 2020-03-26 22-50-34.png

ここまでは大丈夫…
問題のデータベースは次から…

データベースに接続

何度もデータベース接続のコードを書くのが面倒なので、使いまわし用の関数を入れたphpファイルを作ります。

connect.php
<?php
// データベースに接続
function connectDB() {
    $dsn = 'mysql:dbname=データベース名;host=localhost;charset=utf8'; //データベース名とホスト名
    $user='root';   //データベースのユーザー名
    $password='****';    //データベースのパスワード
    try {
        $dbh = new PDO($dsn, $user,$password);
        $dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
        return $dbh;

    } catch (PDOException $e) {         //  データベースに接続出来なかった場合の処理
        print'エラー';      //  エラーメッセージを表示して終了
        exit();
    }
}
?>

PDOオブジェクトを使ってデータベースに接続しています。
使い方はこちら(PDOを使ったPHPでのデータベース基本操作)を参考にさせていただきました。

入力データの確認

スタッフ追加ページのstaff_add.htmlで入力されたスタッフ名とパスワードの確認ページを作ります。
スタッフ名の未入力やパスワードと確認用パスワードが一致していない場合の処理も作っていきます。

add_confirm.php
<?php


    //staff_add.htmlからデータ受取
    $staff_name=$_POST['name'];
    $staff_password=$_POST['pass'];
    $staff_password2=$_POST['pass2'];

    //エスケープ処理
    $staff_name=htmlspecialchars($staff_name,ENT_QUOTES,'UTF-8');
    $staff_password=htmlspecialchars($staff_password,ENT_QUOTES,'UTF-8');
    $staff_password2=htmlspecialchars($staff_password2,ENT_QUOTES,'UTF-8');

    //以下、入力内容確認処理

    if($staff_name==''){
        print'スタッフ名が入力されていません。<br/>';
    }else{
        print'スタッフ名:';
        print $staff_name;
        print'<br/>';
    }

    if($staff_password!=$staff_password2){
        print'パスワードが一致しません。<br/>';

    }

    if($staff_name==''||$staff_password==''||$staff_password!=$staff_password2){
        //入力内容に問題があれば戻るボタンのみ表示
        ?>
        <form>
          <input type="button" onclick="history.back()" value="戻る">
        </form>
        <?php
    }else{
        //MD5方式でパスワードをハッシュ化
        $staff_password=md5($staff_password);
        ?>
        <form method="post" action="add_done.php">
          <input type="hidden" name="name" value="<?php print $staff_name;?>">
          <input type="hidden" name="pass" value="<?php print $staff_password;?>"><br/>
          <input type="button" onclick="history.back()" value="戻る">
          <input type="submit" value="登録">
        <form>
        <?php

    }
?>

エスケープ処理については以下を参考にしました。
PHPでエスケープが必要な時と方法を最短理解!
「何故htmlspecialcharsを通すのか?」を一言でどうぞ

データベースにレコードを追加

次は、前の画面で確認したスタッフ名とハッシュ化したパスワードを受け取って、データベースに追加する処理を作ります。

add_done.php
<?php

require_once 'connect.php';
$dbh = connectDB();

try {

    $staff_name=$_POST['name'];
    $staff_password=$_POST['pass'];
    //エスケープ処理
    $staff_name=htmlspecialchars($staff_name,ENT_QUOTES,'UTF-8');
    $staff_password=htmlspecialchars($staff_password,ENT_QUOTES,'UTF-8');

    $sql='INSERT INTO テーブル名(name,password) VALUES (?,?)';   //SQL命令文 入れたいデータは「?」
    $stmt=$dbh->prepare($sql);    //準備する命令
    $data[]=$staff_name;          //「?」にセットしたいデータを順番に書き出し
    $data[]=$staff_password;
    $stmt->execute($data);        //クエリの実行

    $dbh=null;      //データベース切断

    print $staff_name;
    print 'さんを追加しました。<br/>';

}catch(Exception $e){
    print'エラー';
    exit();
}

?>
<a href="staff_list.php">戻る</a>

これでどこかミスってなければデータベースにユーザー名とパスワードのレコードが追加されてるはず。
(passwordには「test」をハッシュ化したものが入ってます)
Screenshot from 2020-03-26 23-22-07.png

スタッフ一覧

せっかくなのでデータベースに追加したスタッフの一覧を表示させるページも作ります。

staff_list.php
<?php
require_once 'connect.php';
$dbh = connectDB();

try{
    $sql='SELECT name FROM テーブル名 WHERE 1'; 
    $stmt=$dbh->prepare($sql);
    $stmt->execute();

    $dbh=null;

    print'スタッフ一覧<br/>';
    while(true){
        $rec=$stmt->fetch(PDO::FETCH_ASSOC);
        if($rec==false){
            break;
        }
        print $rec['name'];
        print '<br/>';
    }

}catch(Exception $e){
    print 'エラー';
    exit();
}

?>
<br/>
<input type="button" onclick="location.href='./staff_add.html'" value="スタッフ追加">

最後に、最初に作ったスタッフ追加ページに飛ぶ飛ぶスタッフ追加ボタンもつけておきます。

Screenshot from 2020-03-26 23-28-00.png
出来た出来た。追加と表示しかしてないけどとりあえず出来た。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

100日後にエンジニアになるキミ - 6日目 - HTML - HTMLの基礎1

はい、6日目ですが、ようやく言語の方に入っていきます。

ツール類のインストールを終えていない方は
5日目までの内容をみていただき
ツール類を揃えておいて下さいね。

HTMLについて

HTMLとは

HyperText Markup Language

の略でWEBページなどを作成するための
マークアップ言語になります。

マークアップ言語というのは
文章構造などを記述するための形式言語になり
他にはTex , XML , Markdown などetcがあります。

ここで言う
ハイパーテキスト(HyperText)とは
文字通りハイパーなテキストの事ですwww

テキストを超えると言う意味合いから
複数の文書(テキスト)を相互に関連づける仕組みをもつ
記述型の言語と言う事でHTMLと言います。

視覚表現や文章構造などを含めた記述を行うことができます。

通常のテキストファイルというのは文字だけですが
HTMLファイルになると、画像やリンクなども含めることができ
より視覚表現に長けたテキストを作ることができる訳です。

ファイルの最後に
「.html」という拡張子がついたものが
HTMLファイルになります。

HTMLの特徴

HTMLファイルをみるためには二つの方法があります。

・テキストエディターで見る
・ブラウザーで見る

テキストエディターで開いた場合は、
HTMLファイルの中身そのものであるソースコードが表示されます。

WEBサイトを見る場合は
ブラウザーで見ることとなります。

閲覧先のサイトのサーバーにアクセスして
HTMLを読み込んでいるのです。

ブラウザで表示した場合
HTMLのソースコードをブラウザーが解釈し
画面左上から描画が始まります。

このHTMLで書かれたデータを解釈し
画面に表示する文字や画像などの配置を計算することを
「HTMLレンダリング」と言っています。

ブラウザーで見た場合はレンダリングが行われた
段組みされた後の結果を見ることになります。

テキストエディターで見たソースコード(一部)
スクリーンショット 2020-03-26 18.03.17.png

ブラウザーで見たHTMLファイルの結果
スクリーンショット 2020-03-26 18.04.33.png

またこのソースコードの解釈の仕方も
ブラウザによって異なります。

ブラウザのレンダリング用のプログラムのことを
「HTMLレンダリングエンジン」と呼び
ブラウザ毎でレンダリングエンジンが異なるためです。

Trident (Internet Explorer)
EdgeHTML (Microsoft Edge)
Gecko (Firefox)
WebKit (Safari)
Blink (Chromium, Google Chrome, Opera)

ブラウザーによっては正しく表示させるために
ソースコードを書き直す必要が出てくる場合もあります。

HTMLの仕組み

HTMLでは木構造の「HTMLタグ」を用いて
ハイパーリンクや画像等のマルチメディアの埋め込み、
見出しや段落などドキュメントの抽象構造化、
フォントや文字色など見た目の指定が行えます。

HTMLタグは

< で始まり > で終わります。

HTMLの要素(エレメント)は
開始タグ~終了タグに囲まれた全体を指す概念で
・開始タグ(Start-tag)
・内容(Content)
・終了タグ(End-tag)
の3つから構成されます。

また開始タグ内に任意の属性(attribute)と
属性値(value)のペアを含むことができます。

alt
参考(https://bibabosi-rizumu.com/elements-attribute-value/)

この例だと
spanタグで内容はテキスト
属性としてstyle属性があり、属性値はcolor:#ff00ff;

属性値を加える際に、属性値は " で囲みます。

HTML文書の作成

HTML文書はタグを記述し拡張子に.htmlをつければ
HTMLファイルとして保存することができます。

それではHTML文書を作ってみましょう。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>HTML5サンプルだよん</title>
    </head>
    <body>
        <p>HTML5の本文</p>
    </body>
</html>

テキストエディターを開いて
これを打ち込むかコピペしてもらい
出来たら、デスクトップなどに保存してみましょう。

スクリーンショット 2020-03-26 18.24.47.png

それをブラウザーで開いてみましょう。
ファイルをダブルクリックするか右クリックから開くで開けるはずです。

スクリーンショット 2020-03-26 18.24.16.png

結果はこんな感じになったはずです。

このサンプルの解説です。

冒頭に <!DOCTYPE html> を付けるとHTML5として解釈されます。

タグは大文字小文字は区別されないのですが、基本小文字で書けば良いです。

<!-- -->で囲んだテキストのことを「コメント」と呼び
コメントとして書かれたテキストはブラウザには表示されません。
ソースコードにメモ書きしたい場合はコメントの書き方をすれば出来ます。

タグには親子関係があり、タグの中にタグを記述することができます。
親子関係のタグはインデント(字下げ)しておき見やすくすると見やすいです。

ブラウザーに表示されるのは
タグの内容(Content)の部分だけです。
タグそのものは表示されません。

もしタグの名前などがそのまま出てきてしまった場合は
タグを閉じ忘れたり、タグの書き方などが間違っています。
開始 - 終了タグで閉じているかどうか見直してみましょう。

HTMLの基本的構造

HTMLの基本的な構造を表す要素としては

<html>
HTML文書のルート要素

<head>
HTML文書のヘッド部分 を指定する要素
HTML文書自身に関する情報(タイトルやスタイルシートに関する情報など)を指定できる

<body>
HTML文書の本体部分を指定する要素

となっています。
この要素がないとHTMLとしては成立しない形態となります。

<!DOCTYPE html>
<html>
    <head>
        ヘッド部分
    </head>
    <body>
        ボディ部分
    </body>
</html>

HTML要素の中に
HEAD,BODY要素が存在するという構造です。

HEAD(ヘッド)内に記述可能な要素

HEAD要素はheadタグの開始タグを書き、その中に要素を書き終了タグで閉じます。
HEAD内に記述可能な構造を表す要素としては下記があります。

<title>
タイトルを指定,ブラウザのタイトルバーに表示される

<link>
href属性で指定したファイルとの関係を定義する

<meta>
文書の情報を定義する

<style>
スタイル情報を記述,type属性の記述が必要(text/css等)

<script>
スクリプト を記述,type属性(text/javascript)と
meta要素でスクリプトタイプの宣言が必要

<head>
    <title>タイトル<title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link type="text/css" rel="stylesheet" href="sample.css">
    <script type="text/javascript" src="sample.js">< script>
</head>

HEAD要素内に書いたものはtitle以外はブラウザー上では表示はされませんが
WEBサイトの情報になるものであるので
そのWEBサイトに関わることを記述します。

特にWEBサイトの情報の詳細部分である metaタグ は
かなり多くの情報を記載することになりますが
metaタグとlinkタグは終了タグが無くて大丈夫です。

次にscriptタグ,linkタグでは外部のcssやjsファイルを読み込みすることが出来ます。

スタイルシート(stylesheet)とは
構造化文書の見た目を記述するコンピュータ言語のことで
一般的にはCSS(カスケードスタイルシート)が用いられます。

CSS(カスケードスタイルシート)は
文書構造と体裁の分離という理念の実現の為に
提唱されたスタイルシートの仕様の一つで
CSSはHTMLに新たなデザイン機能を備えるものです。

スタイルシートを切り替えて表示を変化,効果の重ね合わせなどが
実現可能になっています。

スクリプト(script)は一般的には Javascript を指し
Javascriptはオブジェクト指向のスクリプト言語です。

多くのウェブブラウザ等は標準化されたECMAScriptを実装しており
WEBサイト上の動的な表現を担っています。

同じオブジェクト指向の言語であるJavaとはあまり関係ありません。
インドとインドネシアくらい違うものだと覚えてください。

通常、HTMLファイルの中にはCSSやJavascriptを
直接書き込んで埋め込むこともできますが
デザイン部分、昨日部分を分けて開発されることが多いため
HEAD部分で外部ファイルとして読み込みを行うことがほとんどです。

BODY要素

HEAD要素はブラウザー上では目に見えない部分を記述する場所ですが
BODY要素は目に見える部分を各場所になります。

BODY要素はbodyタグの開始タグを書き、その中に要素を書き終了タグで閉じます。

<body>
    <p>HTMLの中身</p>
</body>

BODY要素ないは何でも書き入れることが可能です。

まとめ

HTMLのファイルの作り方を押さえておき
基本的な構造(要素)を押さえておこう。

次回はタグについてです。

君がエンジニアになるまであと94日

作者の情報

乙pyのHP:
http://www.otupy.net/

Youtube:
https://www.youtube.com/channel/UCaT7xpeq8n1G_HcJKKSOXMw

Twitter:
https://twitter.com/otupython

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WebサイトをHerokuでデプロイしようとしたら、エラーで躓いた話。

はじめに

制作したWebサイトを取り敢えずHerokuにあげて確認してみたかったのでデプロイしようとしたのですが、
エラーにかなり悩まされたので、同じところで詰まっている方の手助けになれば幸いです。

WebサイトをHerokuでデプロイ

GitHubでコード管理を行っていたので
HerokuとGitHubを連携してHerokuサイトからデプロイしようとしていたところ、

スクリーンショット 2020-03-26 9.49.33.png

上記画像のようなエラーが出てしまいました。

エラーの原因

調べてみたところ、
今回エラーが発生したざっくりとした理由としては
HTMLベースのサイトだとHerokuがアプリとして認識してくれない為でした。

〜〜〜〜〜〜〜〜〜〜〜〜
以下少し詳しく解説します。

まずエラーで何を言われているのかというと、

No default language could be detected for this app.
このアプリではデフォルトの言語を検出できませんでした。

HINT: This occurs when Heroku cannot detect the buildpack to use for this application automatically.
ヒント: これは、Herokuがこのアプリケーションで使用するビルドパックを自動的に検出できない場合に発生します。

とのことです。

ビルドパックは使用するプログラミング言語(PHPやRuby等)に応じて、
実行する前にデプロイされたコードを変換する役割を果たします。
これらのビルドパックは、使用言語に基づいてデプロイされたリポジトリ内で検索されます。
しかし、HTML、CSS、JavaScriptでは検出されません。その為このようなエラーが出たということです。

解決策

index.php
<?php header('Location: /index.html'); ?>

上記画像のように
index.phpファイルを作り、中のコードも同じように記述することで解決しました。
スクリーンショット 2020-03-26 12.03.15.png

↑デプロイ完了後のHeroku画面

〜〜〜〜〜〜〜〜
以下解説します。

今回なぜPHPファイルを作成したのかというと、
WebサイトをPHPアプリとして認識させる為です。

index.phpファイル内の
header関数は、
HTTPヘッダを送信する機能を持っています。

header関数では、
Locationの後ろに
飛び先のファイル名やURLを記述することで
その記述した場所へ移動することが出来ます。

今回はindex.htmlのページに飛ばしたかったので
上記のように記述しました。

まとめ

話をまとめると

今回のエラーの原因は、
HTMLベースのサイトの為アプリ認識してくれなかったこと。
解決策は、
phpファイルを作りアプリ認識してもらえるようにすること。

最後に、
参考にさせていただいたサイトのURLを下記に紹介します。

[Herokuを使って簡単にウェブページをインターネットで公開する方法]
https://qiita.com/reoring/items/bca12aaa5f94b190a488

[単純なHTML/CSS/JSをHerokuにデプロイする時つまずいたこと]
https://qiita.com/hozukikancho/items/b8d475e67a147cd54453

[How to Run a Simple HTML/CSS/Javascript Application on Heroku]
https://medium.com/@winnieliang/how-to-run-a-simple-html-css-javascript-application-on-heroku-4e664c541b0b

[PHPのheader関数でリダイレクト処理を行う方法【初心者向け】]
https://techacademy.jp/magazine/11609

以上です。
最後までご覧くださり、ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【完全初心者】Web系エンジニアを目指す ~LP模写に挑戦(随時更新)~

出産後は赤ちゃんの傍で
在宅Webプログラマーとして働きたいので
これからWeb系エンジニアになるための勉強を始めます
(出産まであと1ヵ月切ったけど…笑)

とりあえず、かなりご無沙汰であったHTML,CSSの復習からスタート。

◆目標

「LP案件」をバンバン取れるようになりたい。

◆やったこと(2020.3.25~2020.3.27現在)

・Photoshop無料期間登録
Photoshopデータからコーディングする方法の動画記事を見る
・HTML,CSSの基本知識がほぼぶっ飛んでることに気づき焦る
・テキストエディタでHTML,CSSの動画を見ながら手を動かす
・作業効率化のために無償のVisualStudioCodeダウンロード
拡張機能などはこちら
こちらのサイトを参考にした
こんな海外プログラマーさんのYoutubeもみたりした
・VisualStudioCodeで動かしてデバッグしてみた
・GoogleCromeで模写参考サイトを覗く
模写参考に使用したサイトたち
・GoogleCrome上で模写参考サイトの検証ページからデバッグしてみた
超★有能なおまとめがあったので、こちらと、こちらも参考にさせてもらった

◆以下、超★有能なおまとめに出会うまでの手順

とりあえず、大まかな構成を確認しつつ、
コーディングの仕方の復習

image.png

超・基本的な構成がそうそう、こんな感じだ!

image.png

VisualStudioCodeだと予測変換で型が一発なのか!
(普通のことなんだろうけど、私的には感動)

image.png

image.png

!だけでも出るのか…(感動)

image.png

有能なおまとめに出会ったので、こちらと、こちらも参考にさせてもらった
(上記のものと同じリンク)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

#【HTML】ウィンドウの大きさでレイアウトがグチャる...【CSS】

ウィンドウの大きさ変更でレイアウトがグチャる...

そんな時は、widthで、コンテンツの入ったcontainerを固定しちゃいましょう!

これにより、ウィンドウの幅の変更に対応出来ます

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【HTML】ウィンドウの大きさでレイアウトがグチャる...【CSS】

ウィンドウの大きさ変更でレイアウトがグチャる...

そんな時は、widthで、コンテンツの入ったcontainerを固定しちゃいましょう!

これにより、ウィンドウの幅の変更に対応出来ます

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HTML決まり文句

HTMLの決まり文句

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title></title>
</head>
<body>
    <header>
    </header>
    <footer>
    </footer>
</body>

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者によるプログラミング学習ログ 273日目

100日チャレンジの273日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
273日目は、

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む