PHP PDO 〜MySQLにアクセスする〜

イントロダクション

現在、GoogleMapを使用したブラウザアプリの作成中です(2019-07-11)。
実装中につまづいたのでメモがてらに記載します。
<作成プログラム概要>

  • JSでのGoogleMap表示
  • PHPでの入力データをDBに登録

こんな感じです。

PDO to MySql

確認するポイント

  • phpinfo()でPDOの使用が可能か確認

そして確認ができたらMySQLでのPDOのインストール方法(使用可能か確かめる)とDPDO使用方法を参照して使い方を理解する。

<作成したコード>

// DBアクセス
$dns = 'mysql:host=localhost;dbname=test_dbname';
$username = DB_USER;
$password = DB_PASS;
$driver_options = [
    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
];
$insertQuery = "INSERT INTO AREA_INFO(AREA_ID, INFO_NAME, INFO_URL, INFO_IMAGE, INFO_LAT, INFO_LNG, OWNER_ID, UPDATE_DATE) VALUES(?, ?, ?, ?, ?, ?, ?, ?)";

try {
    $pdo = new PDO($dns, $username, $password, $driver_options);
echo "tee";
    $pdo->prepare($insertQuery);
    $pdo->bind(1, 1);
    $pdo->bind(2, $name);
    $pdo->bind(3, $url);
    $pdo->bind(4, $lat);
    $pdo->bind(5, $lng);
    $pdo->bind(6, $imgTmp, PDO::PARAM_LOB);
    $pdo->bind(7, 1);

} catch(Exception $e) {
    print($e->getTraceAsString());
}

PreparedStatement

SQLを実行するときによく使うのがプリペアードステートメント(PreparedStatement)です。
早い話が、SQLの値部分(?)にパラメータを渡してやるものです。
Sample

  • INSERT INTO A_TBL(COL_A, COL_B) VALUES(?, ?);

というSQLクエリを実行(execute)しようとしたときに下のようにコードを書きました。

    $pdo->prepare($insertQuery);
    $pdo->bind(1, 1);
    $pdo->bind(2, $name);
    $pdo->bind(3, $url);
    $pdo->bind(4, $lat);
    $pdo->bind(5, $lng);
    $pdo->bind(6, $imgTmp, PDO::PARAM_LOB);
    $pdo->bind(7, 1);

エラリました。。。
マニュアルを見ると「bind」なんてメソッドはありませんでした。。。
なのでマニュアルに習い以下のように書き換えました。

try {
    $pdo = new PDO($dns, $username, $password, $driver_options);
echo "tee";
    $statement = $pdo->prepare($insertQuery);
    $statement->bindParam(":id", $id);
    $statement->bindParam(":name", $name);
    $statement->bindParam(":url", $url);
    $statement->bindParam(":img", $imgTmp, PDO::PARAM_LOB);
    $statement->bindParam(":lat", $lat);
    $statement->bindParam(":lng", $lng);
    $statement->bindParam(":owner", $ownerId);

    $statement->execute();

} catch(Exception $e) {
    print($e->getTraceAsString());
}

これでDBにデータの登録ができるようになりました。作成した画面はこちらです。

ちなみにSELECT文などは「query()」が使える。

try {
    $pdo = new PDO($dns, $username, $password, $driver_options);

    foreach ($pdo->query($selectQuery) as $row) {
        $tags = $tags . '
' . 'img src="data:image/jpg;base64,' . $row['INFO_IMAGE'] . '" alt="写真"' . '/div'; } // コネクションの解放 $pdo = null; } catch(Exception $e) { print($e->getTraceAsString()); } // レスポンスに出力 print($tags);

でわでわ。。。



PHP PDO 〜invalid data source name〜

invalid data source name

表題のエラーが出てすごく困っていました。
下のようにコードを作成し最後のnew PDOの部分でエラーになるので「おかしい!」と悩んでいました。
参考サイトPHPマニュアル

$dns = 'mysql:host=localhost;dbname=testdb';
$username = 'user';
$password = 'pass';
$driver_options = [
    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $username, $password, $driver_options);

解決

スペスミスでした(笑)

$dns = 'mysql:host=localhost;dbname=testdb';
$pdo = new PDO($dsn, $username, $password, $driver_options);

わかりづらいのですが、「$dns」と「$dsn」で間違っていたのでコンストラクタにから文字が渡されていました。。。

解決方法

以下のようにtry〜catchでエラーとレースを出力しました。

} catch(Exception $e) {
    print($e->getTraceAsString());
}

これでエラーの詳細が出力されるので一発で解決できました。

エラー出力、ハンドリングはちゃんとやりましょう(笑)

でわでわ。。。



PHP Ajax 〜リクエストが取得できない〜

AjaxとPHP

XMLHttpRequestでPHPにリクエストを飛ばしたときにはまりました。
JSONでリクエストを送信したもののPHPでファイルデータが取得できない。。。バイト文字を送信するのも一つですが…

解決

参考サイト
取得するのにFile形式で取得するようだった。。。。

$post_body = file_get_contents('php://input');


ここにたどり着くのに結構かかってしまいました。。。
みなさんお気をつけて。。。

取得はできたけど、データの操作が出来ず…

結局はフォームデータにファイルをセットして送信しました。

注意としては、XmlHttpRquestのヘッダーに何も設定しない状態でリクエストを飛ばす事、これを見つけるのに苦労しました(笑)

次は、PHPで、入力データ(文字列とファイル)をMySqlに登録しようと思います。

既に、試したのですがPDOが使えないサーバがあるので、php Infoで確認した方が安全です。

でわでわ。。。



Ajax PHP 〜Ajax通信エラー No ‘Access-Control-Allow-Origin’ 〜

No 'Access-Control-Allow-Origin'

こんなエラーが出ました。JavaScriptで以下のようなコードを実行したときです。

    xhr = new XMLHttpRequest();
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange = recieveResponse
   xhr.open('GET', 'https://zenryokuservice.com/tools/maps/InsertMapInfo.php?param=test', true);
    xhr.send();


SampleMap.html:1 Access to XMLHttpRequest at 'https://zenryokuservice.com/tools/maps/InsertMapInfo.php?param=test' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

答え

異なるドメインから呼び出すと、このようになるようです。
セキュリティの問題なようです。まぁ確かによろしくはないですね。。。参考サイトより

対応

実はこのコードは自分のPCから直接実行しました。運用するときは自分のレンタルサーバー上にJSを配置するのでこの問題は起きません。。。
なのでサーバーにアップして再度実行します。

こんな感じでAjax通信のテストを完了できました。

作成したものはここにあります。

https://zenryokuservice.com/sample/js/SampleMap.html

次は

作成したフォームを送信します。



関連ページ

  1. JS GoogleMaps API 〜オリジナル・データマップを作ろう〜
  2. Github page Github pageでリポジトリの情報を公開しよう〜
  3. 夢を形にする① 目標ブレーク〜じゃんけんゲームの場合〜
  4. プログラム 習得 順序1 概要
  5. Githubページ関連

  6. Github page Github pageでリポジトリの情報を公開しよう〜
  7. Github 使い方〜リポジトリにライセンスを設定する〜
  8. Github 使い方〜Issueでやることを整理〜

PHP 暗号化 〜openssl_encryptを使う〜

イントロダクション

前回、レンタルサーバー上でJavaを起動しようとして、結局は起動できませんでした。。。

結局は、PHPで暗号化することにしました。そして、サンプルがあったのでそれを失敬して、作成しました。

/** 暗号化メソッド */
function encrypt($post_str, $passphrase, $iv) {
    //暗号化用のメソッドを指定
    $method = 'AES-256-CBC';
    //利用可能な暗号メソッドの一覧を取得するには openssl_get_cipher_methods() を使用;
    /*
    $ciphers = openssl_get_cipher_methods();
    var_dump($ciphers);
    */
    //暗号化を実施
    $options = OPENSSL_RAW_DATA;
    return openssl_encrypt($post_str, $method, $passphrase, $options, $iv);
}

/** 復号メソッド */
function decrypt($post_str, $passphrase, $mst_iv) {
    //暗号化用のメソッドを指定
    $method = 'AES-256-CBC';
    $iv = getIv($method);
    //復元を実施
    $options = OPENSSL_RAW_DATA;
    $res = openssl_decrypt($post_str, $method, $passphrase, $options, $mst_iv);
vreturn $res;
}

/** ivを取得する */
function getIv($method) {
    //暗号初期化ベクトル (iv) の長さを取得
    $iv_size = openssl_cipher_iv_length($method);

    //暗号モードに対するIVの長さに合わせたキーを生成します
    return openssl_random_pseudo_bytes($iv_size);
}

上記のコードは暗号化と復号化の処理(メソッド)です。これを使用して実際に暗号と復号を行います。サンプルとしてブラウザで入力できるものを作りました。
良かったら見てやってください。

こんな感じで、暗号化する文言を入力した後に「暗号化出力」以下の部分に結果が出力されます。「復号化処理」の結果も同じ場所に出力されます。
暗号化処理のサンプル

インターネットに繋がるのが「普通」の時代なので「セキュリティ」がとても重要な時代ですね。会社間で使用するデータなどは暗号化が必須になりますので、今後IT業界で何かやろうとしている人は知っておくと便利なのではないでしょうか?

でわでわ。。。

関連ページ

JS Google Maps API 〜オリジナル・データマップを作ろう〜

Google Maps APIを使う

Google Maps API(javascript版)を使用して便利な地図アプリを作成します。そのためにGoogleのAPIを使用するための手続きをやります。
参考サイトはこちらです。

手順1

とりあえずはこちらのサイトを開きます。

そして、下のようなアイコンがあるのでそれをクリックします。

見つからない場合は下のように

をクリックして

GoogleMapを選択します。そして詳細をクリック

認証情報を作成

APIキーを選択

こんな感じでできました。

以下のような形で一定量は無料で使えます。詳細はGoogleに聞いてみるしかなさそうです。。。(Google Japanあたり?)

実装

HTMLで表示するので、JavaScriptでの実装を行います。
そしてこちらがJSのドキュメントです。JavaとかそこらへんのAPIも揃えているようなので、目移りしてしまいますね(笑)

そして英語のなので当然! Google翻訳でドキュメントを読みます。

嬉しいことに

上記のドキュメントサイトにサンプルコードがありました。
このコピーしたコードの32行目に以下のようなコードがあります。

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY" callback=initMap''
async defer></script>

ここの「YOUR_API_KEY」を上記で作成(取得)したキーを貼ります。その実行結果がこちらです。シドニーが表示されています。オーストラリア。。。いいですね。ジンギスカンですか。。。

とりあえずは初期表示ハローGoogle Mapと言うことで。。。

しかしエラーが

画面を表示して一瞬は正常に表示されたけどAPIキーの設定がまだだったのでエラー。。。

APIキーの設定をする

デフォルトの状態ではAPIの制限などが入っていないので問題ないのですが、自分は以前使用したものがありウェブサイトの指定を行なっていました。
なので今回使用するURLを追加しました。

最後に「*」アスタリスクをつけないとサブディレクトリが対象に含まれません。。。

アカウントを有効化

この作業を行わないとAPIキーが有効になりません。ちょっとためらうのが「支払い設定」でした。
しかし、入力するページには下のような文言があり、無料での使用は可能だと言うことがわかります。「有料アカウントに手動でアップグレードしない限りは・・・」と言う記載があります。

そんなわけで、入力を続けていくと下のような画面が出てきます。これで設定完了!

そして、URLの制限などがないことを確認します。
そして表示!

まだエラーが。。。

画面の表示はできるけど、シドニー(オーストラリア)は表示できるけど、日本は表示できない事件がありました。
原因は

{lat: 141.33432, lng: 141.434334}

のように北緯の値が90度以上になっていて表示できなかったというわけでした。
正しくは

{lat: 43.064157, lng: 141.353364};

でした。

追伸

Google Mapの座標を取得するページでの経度と緯度の値部分の順番がそのままではないので注意です。

lat: 経度
lng: 緯度

でわでわ。。。

関連ページ

  1. Github page 〜Github pageでリポジトリの情報を公開しよう〜
  2. 夢を形にする① 目標ブレーク〜じゃんけんゲームの場合〜
  3. プログラム 習得 順序1 概要
  4. Github page 〜Github pageでリポジトリの情報を公開しよう〜
  5. Github 使い方〜リポジトリにライセンスを設定する〜
  6. Github 使い方〜Issueでやることを整理〜










PHP TwitterAPI ツイートを取得

ツイートを取得する時のめもです

できたもの

https://zenryokuservice.com/mokuhyoAP.php

ツイート表示のためのテンプレートHTML

取得もとはこちら(Twitter/publish?)

ツイート取得時のJSONの中身

ツイートの取得時に「json_decode()」を使用します。というか使用していました。それはここからTwitterAPIPHPラッパークラスにあるコードを使わせてもらったからです。
そして、案の定手こずりました。以下は取得したJSONのプロパティ一覧です。

["truncated"]=> bool(false) 
["entities"]=> object(stdClass)#5722 (4) { 
    ["hashtags"]=> array(0) { } 
    ["symbols"]=> array(0) { } 
    ["user_mentions"]=> array(0) { } 
    ["urls"]=> array(1) { 
        [0]=> object(stdClass)#5723 (4) { 
            ["url"]=> string(23) "https://t.co/ucfr5Mp3pk" 
            ["expanded_url"]=> string(37) "https://zenryokuservice.com/mokuhyoAP" 
            ["display_url"]=> string(29) "zenryokuservice.com/mokuhyoAP" 
            ["indices"]=> array(2) { [0]=> int(75) [1]=> int(98) } 
        } 
    } 
} 

["metadata"]=> object(stdClass)#5724 (2) { 
    ["iso_language_code"]=> string(2) "ja" 
    ["result_type"]=> string(6) "recent" 
} 

["source"]=> string(82) "Twitter for iPhone" 
["in_reply_to_status_id"]=> NULL 
["in_reply_to_status_id_str"]=> NULL 
["in_reply_to_user_id"]=> NULL 
["in_reply_to_user_id_str"]=> NULL 
["in_reply_to_screen_name"]=> NULL 
["user"]=> object(stdClass)#5725 (41) { 
    ["id"]=> int(2378007752) 
    ["id_str"]=> string(10) "2378007752" 
    ["name"]=> string(12) "たくのじ" 
    ["screen_name"]=> string(13) "java_takunoji" 
    ["location"]=> string(0) "" 
    ["description"]=> string(288) "JavaでRPIなどの上で動くゲームを仕様から作成中。 好きな言葉は「ロッケンロールは1日にして成らず」#PGボックス #Java #opencv Create a game based java on RPi etc ... My favorite word is “ロッケンロールは1日にして成らず” thanks!" 
    ["url"]=> string(23) "https://t.co/tYxRX8YCof" 
    ["entities"]=> object(stdClass)#5726 (2) { 
        ["url"]=> object(stdClass)#5727 (1) { 
            ["urls"]=> array(1) { 
                [0]=> object(stdClass)#5728 (4) { 
                    ["url"]=> string(23) "https://t.co/tYxRX8YCof" 
                    ["expanded_url"]=> string(39) "https://zenryokuservice.com/roadMap.php" 
                    ["display_url"]=> string(31) "zenryokuservice.com/roadMap.php" 
                    ["indices"]=> array(2) { [0]=> int(0) [1]=> int(23) } 
                } 
            } 
        }
    ["description"]=> object(stdClass)#5729 (1) { 
        ["urls"]=> array(0) { } 
    } 
} 

["protected"]=> bool(false) 
["followers_count"]=> int(1756) 
["friends_count"]=> int(3297) 
["listed_count"]=> int(1) 
["created_at"]=> string(30) "Sat Mar 08 02:49:23 +0000 2014" 
["favourites_count"]=> int(5035) 
["utc_offset"]=> NULL ["time_zone"]=> NULL 
["geo_enabled"]=> bool(true) 
"verified"]=> bool(false) 
["statuses_count"]=> int(957) 
["lang"]=> string(2) "ja" 
["contributors_enabled"]=> bool(false) 
["is_translator"]=> bool(false) 
["is_translation_enabled"]=> bool(false) 
["profile_background_color"]=> string(6) "C0DEED" 
["profile_background_image_url"]=> string(48) "http://abs.twimg.com/images/themes/theme1/bg.png" ["profile_background_image_url_https"]=> string(49) "https://abs.twimg.com/images/themes/theme1/bg.png" ["profile_background_tile"]=> bool(false) 
["profile_image_url"]=> string(74) "http://pbs.twimg.com/profile_images/976105570573762560/jqMlT-a__normal.jpg" ["profile_image_url_https"]=> string(75) "https://pbs.twimg.com/profile_images/976105570573762560/jqMlT-a__normal.jpg" ["profile_link_color"]=> string(6) "1DA1F2" 
["profile_sidebar_border_color"]=> string(6) "C0DEED" 
["profile_sidebar_fill_color"]=> string(6) "DDEEF6" 
["profile_text_color"]=> string(6) "333333" 
["profile_use_background_image"]=> bool(true) 
["has_extended_profile"]=> bool(false) 
["default_profile"]=> bool(true) 
["default_profile_image"]=> bool(false) 
["following"]=> bool(false) 
"follow_request_sent"]=> bool(false) 
["notifications"]=> bool(false) 
["translator_type"]=> string(4) "none" } 
["geo"]=> NULL ["coordinates"]=> NULL 
["place"]=> NULL ["contributors"]=> NULL 
["is_quote_status"]=> bool(false) 
["retweet_count"]=> int(0) 
["favorite_count"]=> int(2) 
["favorited"]=> bool(false) 
["retweeted"]=> bool(false) 
["possibly_sensitive"]=> bool(false) 
["lang"]=> string(2) "ja" 
}

まぁ全部使わないのでここら辺にしておきます。

でわでわ。。。










PHP WordPress〜テンプレート関数をWP外部から使う〜

WordPressのライブラリをロードすればおっけ!カテゴリの取得、ヘッダ、フッタの取得は確認できました。以下のコードで動くようになります。

/** Loads the WordPress Environment and Template */
require( dirname( __FILE__ ) . 'ワードプレスのフォルダまでのパス/wp-blog-header.php' );









PHP 楽天API WordPress〜楽天プラグインを使う〜

イントロダクション

楽天APIを使用して商品検索を行うことはできる様になりました。

次は商品を紹介するためのページを作成します。そして最後にプラグインのしよう結果を記載します。

少しずつ確実に。。。

人間誰しも、いっぺんになんでもできません。なので1つずつ確実にやっていこうと思います。

とはいえ「確実」と言っても「確実に表示する」という意味でやって行きます。

前回はただ単に表示しただけなので、今回は少し色気をつけてみました。

取得したデータをテーブルタグを使用して揃えたものをループしただけです。デザインは苦手なのでこんなくらいがいっぱいいっぱいです。

それでも、まぁ形にはなったかな?と思います。ついでなのでデータを再検索する様に処理を追加しました。

function researchRctn() {
	var param = document.getElementById('category').value;
	console.log(param);
	location.href = "http://zenryokuservice.com/project/rakuten/php/rakutenCatalog.php?category=" + param;
}

上のコードを追加してボタンのクリックで起動する様にしました。

< input id="category" type="text" /><button>商品をリロード</button>

ついでに楽天プラグインを使って見る

「R」ボタンを押下して表示した文字は「rakuten ids=XXX」の様な文字が下に表示されただけですが、これはちゃんと投稿後にイメージなどが表示されるのでしょうか?