PGボックス 記事一覧

PGボックス記事一覧

Java Basic Lv1-10

Java Basic Step1-3

目標達成プロジェクト (サンプル2)

ND4J

Twitter API

Google Maps

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




JS GoogleMap 〜既存ソースの修正〜

イントロダクション

前回、GoogleMapのJavaScript APIの使い方について触れました。

今回は、今迄に作成したソースに改修を加えます。

サンプル作成中のページはこちらです。

改修内容

「作成したSELECTボックスの値をDBに登録する。」です。
現状の画面は下のような感じです、表示するには「ログイン」を行う必要があります。

![](http://zenryokuservice.com/wp/wp-content/uploads/2019/08/スクリーンショット-2019-08-28-21.20.41-300x188.png)

#### 追加する処理
1. 作成したSELECTボックスの値を取得する処理
2. 取得した値をサーバー(PHP)に送信する処理(実際には値を設定するだけ)
3. ・JS(クライアントサイド)から送信した値を、サーバ(PHP)で受け取る
4. ・受け取ったデータをDBへの登録処理に追加する
### 具体的に
1. データ送信ボタンを押下した時に、SELECTボックスの値を取得する
2. 選択された値をAjaxでの送信するデータオブジェクトへ設定する
3. PHP.送信されたリクエストを取得、その時の項目を追加する
4. 追加した項目の値をSQL(登録処理)に追加する

以上のような処理を実装します。現状は下のような画面が表示されています。下のセレクトボックスは値を変更しても何も変わりません。
![](http://zenryokuservice.com/wp/wp-content/uploads/2019/08/スクリーンショット-2019-08-28-21.18.00-300x145.png)

### 現状のJS

/** セットしたデータをPHPに送信する */
function postData() {
    ajaxPost();
}

/** Ajax送信処理 */
function ajaxPost() {
    xhr.open('POST', 'https://zenryokuservice.com/XXXXX.php', true);
    // xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;  charset=UTF-8"');
    xhr. responseType = 'text';
    xhr.onreadystatechange = recieveResponse;
    // POSTデータを設定する
    var data = createJSON();
    console.log(data);
    try {
        xhr.send(data);
    } catch(e) {
        console.log(e);
    }
}

/** POST送信するデータ(JSON)を作成する */
function createJSON() {
    var data = new FormData(document.getElementById("mapData"));
    return data;
}

よく見たら。。。formから直接送信データを作成しているようでした(笑)
つまり、SELECTボックスに名前をつけて、PHP側でそれを取得するようにしてやれば良いということです。

### 修正箇所

SELECTボックスの属性部分に name="categoryId" を追加します。

// 20190828
$statement->bindParam(":categoryId", $categoryId);

INSERT INTO テーブル名(追加項目名) VALUES(: categoryId)のようにSQLに項目を追加します。
画面からテストがてらにデータ追加!キャプチャ取ったがよくわからないです。。。すいません。。。

![](http://zenryokuservice.com/wp/wp-content/uploads/2019/08/スクリーンショット-2019-08-28-21.51.29-300x14.png)

登録した結果は下のように表示されます。

![](http://zenryokuservice.com/wp/wp-content/uploads/2019/08/スクリーンショット-2019-08-28-21.52.50-262x300.png)

[対象のページはこちらです。](https://zenryokuservice.com/sample/js/SampleMap.html)

## まとめ
今回の改修作業は、以下の点を変更するものでした。
1. 画面の入力項目にカテゴリを追加する
2. Formでデータを送信するのでSELECTボックスに名前をつける
3. PHPで受信したデータを取得
4. SQLに項目を追加、パラメータも追加

他の処理は触りませんでした。下手に触ると。。。というのもありますが、せっかく作ったものですので、余計な改修はしたくありません。手間もかかるし。。。
つまり、設計をある程度ちゃんとやっておけば最低限の修正で済むし、作ったもの(コード)を長く使用できるというわけです。

でわでわ。。。



Java Mid Basic 〜Lv2_6_Javaの基本(プロパティファイルを読む)ゲームループ付き〜

イントロダクション

前回までに以下のような事をやってきました。

  1. Java Mid Basic 〜Lv1Javaの基本を理解する(ゲームループ付き)〜
  2. Java Mid Basic 〜Lv2_Javaの基本(コードの書き方)ゲームループ付き〜
  3. Java Mid Basic 〜Lv2_1_Javaの基本(四則計算)ゲームループ付き〜
  4. [Java Mid Basic 〜Lv2_2_Javaの基本(リファクタリング)ゲームループ付き〜]()
  5. Java Mid Basic 〜Lv2_3_Javaの基本(リファクタリング実践)ゲームループ付き〜
  6. Java Mid Basic 〜Lv2_4_Javaの基本(Dirコマンドを作る)ゲームループ付き〜
  7. Java Mid Basic 〜Lv2_5_Javaの基本(コマンド履歴を作る)ゲームループ付き〜

<各項目の概要と目的>

  1. ハローワールドを行い、コードを書いて動かす:これによりメインメソッドの存在とコンソールへの出力方法を知ります。
  2. 動かしてみたので、その内容を理解します。
  3. とりあえずのレベルで内容を理解したので、実際にコードを書いて動かします。自分でコードを考えて実装→起動を行うとプログラミングの面白みも見えてくるかと思います。
  4. 書いたコードをレベルアップします。今後この「リファクタリング」はどのレベルになってもついてきます。レベルが高ければ高いほど難易度も上がっていきます。
  5. 理論的なことをやったのであとは実践です。これも「どのように整理してやれば「拡張性、保守性、パフォーマンス」の面で良いものができるか考えるのである意味「永遠のテーマ」です。(笑)
  6. 今度は、入力した文字によっていろんな処理を実装できるようにプログラムを改造していきます。サンプルとして「Dirコマンド」のようなカレントディレクトリ(現在いるフォルダ)のファイル一覧を取得する処理を実装しました。
  7. javaに初めからついているクラス「List」を使用してコマンド履歴を出力するプログラムを作成します。ここではjava.utilパッケージについて記載しています、今後はこのパッケージにあるクラスを何個か使用します。

プロパティファイル

プロパティファイルを使用するのもjava.utilパッケージにあるクラスを使用します。「プロパティファイル」とは拡張子がproperiesのファイルを指します。「*.properties」
このファイルはキーと値がセットになっています。具体的には下のような感じです。

ads="グーグルアドセンス"
win="ウィンドウズ"
mac="マッキントッシュ"

このようなファイルを作成し、これを読み込んでプログラム中で使用します。
今回の使い方は「コマンドをキーにして値を表示する」というような形でやろうと思います。

IN: ads
OUT: グーグルアドセンス

設計

前提として、前回までのコードに追加修正を加える形で実装します。

  1. コンストラクタでプロパティファイルを読み込みます。
  2. プロパティファイルにあるキー(コマンド)を入力した時はプロパティファイルの値を表示
  3. それ以外のコマンド(キー)は前回までと同じ動き

つまり

プロパティフィルにあるキーが存在すればそれを出力して、それ以外はいままで通りということです。

実装

今回のポイントはプロパティファイルを読み込むところです。
プログラムが動き始めたら即ファイルを読み込んでおきたいので、コンストラクタで読み込むように実装します。
そして、Propertiesクラスはフィールド変数として使用します。
ちなみにファイルまでのパスを指定しますが、ビルドパスを基準にパスを記載するのでちょいと注意が必要です。
resources/test.properties>resources/test.propertiesを読み込みたい場合は「ビルドパスがresourcesにつながっていることを確認します。

そしてコードは下のような感じです。

/** コンストラクタ */
public Lv2_6_Properties() {
    commandList = new ArrayList();
    prop = new Properties();
    try {
        // resources/
        prop.load(getClass().getResourceAsStream("test.properties"));
    } catch (IOException e) {
        e.printStackTrace();
        // エラーコード-1をセットしてプログラム終了
        System.exit(-1);
    }
}

ポイントの部分はprop.load(getClass().getResourceAsStream("test.properties"));の部分です、ここではPropertiesクラスのload()メソッドを使用してInputStreamからプロパティファイルを読み込みます。
getClass().getResourceAsStream("パス")で対象ファイルのInputStreamを取得します。
具体的にはビルドパスにつながっているディレクトリがルート「/」になるので「/test.properties」が対象のパスになりますが、環境によりルートが違う場合があります。
作成したコードはこちらです。
そして、実行結果です。



Java Mid Basic 〜Lv2_Javaの基本(コードの書き方)ゲームループ付き〜

イントロダクション

前回は、とりあえず入力して画面に表示するものを作成しました。こんな感じです。

動画は、作成中にデバッックしたものです。ちなみにバグもあります。
とりあえずは「動いた!」という感動を味わっていただきたく思い中途半端ですが、アプリとして動くものを作成しました。
コードはGitにアップしています。

最終的にはコンソールゲームを作ります。

AP概要Lv2

標準入力を受け付けて、以下のような動きをします。

  1. 入力された文字が「hello」の時はコンソールに「Hello World!」と表示する。
  2. そのほかの文字を入力したら「想定外の入力です」を表示する。

四則計算をする

今回のメインになる実装を行います。前回の記事で問題を出しました。ちょっと難しい問題でした。上の動画はデバック中の動画になります。バグも残っています(笑)。

まずは書いたコードの理解

前回作成したコードをもう一度眺めてみます。

public class Lv2HelloWorld {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        while(true) {
            System.out.print("入力してください: ");
            String inStr = input.nextLine();
            if ("hello".equals(inStr)) {
                System.out.println("Hello World!");
            } else {
                System.out.println("想定外の入力です");
                break;
            }
            System.out.println("Next command ... ");
        }
        System.out.print("AP is fiinished. Bye!");
    }
}

頭(行の先頭)からコードの意味を記載していきます。

クラスの定義

上のコードで行くと、下の部分がクラス定義になります。

public クラス名{ .... }

このクラス名はなんでも良いのですが、下のルール(大雑把な規約)にしましょう。ちなみにCheckStyleというEclipseのプラグイン(標準装備)を使用すると簡単に規約違反が見つけられるので便利です。参考サイト

  • メタ文字:%/\&'*)など、これらはEclipseなどのIDE(開発ツール)を使用するとエラーが出るので安心です。
  • Javaのクラスはアッパーキャメルケース("AppaKyameru"のように書く)を使用します。
  • Javaのメソッドはキャメルケース("appaKyameru"のように書く)を使用します。

とりあえずはこんなところを気をつけましょう。

メイン・メソッドの定義

まずは動かしたいので「メインメソッド」を作成します。メインメソッドは以下のような特徴があります。

  1. メソッドの定義は1つだけ、ほかの書き方はない。
  2. 必ずこのメソッドが動く
  3. 引数は「プログラム引数」になる

プログラム引数

プログラム引数はEclipseで使用する場合は下のように値を渡してあげます。つまりString[] argsの部分が引数であり、下のように設定してアプリを起動すると変数「args」に"プログラム引数1"のように値を渡せます。
注意として、プログラム引数は「String」型のデータになります。

ちなみに「データ型」に関しては後々に触れますが、現在使用しているデータ型は「int」「String」があります。

int型

調べてみると「???〜???までの整数」などのように記載されてますが、早い話が、範囲指定はあるけど(正負の)整数です。Stringなどの「オブジェクト型」とか「参照型」など(同義です)と違い、直接の値(メモリの領域)を保持します。

String型

これはjava.lang.Stringというクラスの型になります。intと違い「クラス」なので「null」が存在します。よく「参照型」とか「オブジェクト型」などと呼ばれます。早い話が「NULLが存在する型」なんだな!と理解してくれればOK!今後深く理解していきます。int型などのように直接、値を持つ変数と違いオブジェクトへの参照(ポインタ)を変数に持ちます。だからNULLがあるのです。

次は実装

すでに書いたコードに追記・編集していきます。前回作成したメインメソッド部分では「Hello World」と「想定外 ....」を出力するだけだったので、この部分を拡張します。
元のコード

public static void main(String[] args) {
    System.out.println("プログラム引数のサイズ:" + args.length);
    for (int i = 0; i < args.length; i++) {
        System.out.println("プログラム引数:" + args[i]);
    }
    Scanner input = new Scanner(System.in);

    while(true) {
        System.out.print("入力してください: ");
        String inStr = input.nextLine();
        if ("hello".equals(inStr)) {
            System.out.println("Hello World!");
        } else {
            System.out.println("想定外の入力です");
            break;
        }
        System.out.println("Next command ... ");
    }
    System.out.print("AP is fiinished. Bye!");
}

編集後のコード

public static void main(String[] args) {
    // 今回は作成したこのクラスを使用します。
    Lv2_1_Calculatie myClass = new Lv2_1_Calculatie();

    Scanner input = new Scanner(System.in);

    while(true) {
        System.out.print("入力してください: ");
        String inStr = input.nextLine();
        if ("hello".equals(inStr)) {
            System.out.println("Hello World!");
        } else if (inStr.matches("[0-9].*")) {
            int answer = myClass.calculate(inStr);
            System.out.println("答えは:" + answer + "です。");
        } else {
            System.out.println("想定外の入力です");
            break;
        }
        System.out.println("Next command ... ");
    }
    System.out.print("AP is fiinished. Bye!");
}

具体的に下の部分が変わりました。

Lv2_1_Calculatie myClass = new Lv2_1_Calculatie();
} else if (inStr.matches("[0-9].*")) {
    int answer = myClass.calculate(inStr);
    System.out.println("答えは:" + answer + "です。");

new Lv2_1_Calculatie()の部分は作成したクラスのインスタンスを取得しています。
インスタンス化すると「インスタンスメソッド」が使えるようになります。

インスタンスメソッドとスタティックメソッド

インスタンスメソッド:A a = new A();のように「new」してから使用する
スタティックメソッド:A.staticMethod()のようにクラス名.メソッド名で呼ぶことができる
上のような違いがあります。

まとめ

クラスとメソッドの書き方、メソッドの種類について触れました。結局計算する部分には触れませんでしたので次回触れようと思います。
でわでわ。。。



  1. Java Basic Level 1 Hello Java
  2. Java Basic Level2 Arithmetic Calculate
  3. Java Basic Level3 About String class
  4. Java Basic Level 4Boolean
  5. Java Basic Level 5If Statement
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 Traning of If statement
  8. Java Basic Level8 How to use for statement
  9. Java Basic Level 8.5 Array
  10. Java Basic Level 9Training of for statement
  11. Java Basic Level 10 While statement
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1
  17. Java Basic JUnit 〜テストスイートの作り方〜

JS 非同期 POST 〜非同期通信でのPOSTリクエスト〜

イントロダクション

前回KMLファイルがなんたら。。。と記載しましたが、結局のところはGoogle Mapの選択した位置にピンを落とす処理を追加しました。

現在の作成物はこちらのURL

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

非同期通信処理(Ajax)

今回は、ここから非同期で記載した情報をサーバーに送信、JSONファイルを出力する処理を実装しようと思います。
早速ですが、非同期通信について触れておきます。

非同期通信とは

<同期通信>
HTMLフォームを使用して画面を遷移したり画面をリロードしたりするようなURLを更新するような通信のことを同期通信と言います。まぁ通常のリクエスト送信だと思っていただいて間違い無いと思います。

<非同期通信>
それに対して、非同期は何が違うのかというと画面の一部分を更新するときによく使います。
画面を表示したときに「loading ....」なんて表示されているのがこれです。
<同期通信の場合>
リクエスト送信した後に「レスポンス(次のページを受け取る)を待ちます。
<非同期通信>
リクエスト送信した後に「レスポンス」を待ちません。
なので「loading ...」なんて処理を行いながら「レスポンスが帰ってくる」のを待っています。

ポイント

レスポンスを待たなくて良いので次の処理が実行できるというわけです。「待ち」の時間が減るのでユーザーに優しい実装になります。

今回の用途

地図上の情報を取得、写真をサーバーに送信しJSONという形で保存しようという処理を実装しよう、というお思惑です。
前回記載しました内容の処理を実装します。

JavaScript

最近ではAngluarとかJQueryとかいろんなもの(フレームワーク?)がありますが、面倒なので使用しません。HTML5の仕様読みましたが、かなりの範囲を網羅する形でAPIが提供されているので、わざわざ他のJSライブラリなどを使用しなくて良いと思った次第です。
→話(使用する部品)がややこしくなるのであまり使いたくありません(笑)。

XmlHttpRequest

久しぶりに使用します。非同期通信を行うときに使用するオブジェクトです。他のライブラリなどはこいつを使用しているのでハナっからこの部品を使ってしまいます。APIドキュメントはこちらにあります。ドキュメントページからコードを失敬。。。
こいつをベースにして、ファイルなどのデータを送信する処理を実装しようと思います。

あとは、ソースを眺めながら考えます(笑)。

実装の流れ

先にサーバー側の実装を行います。これはクライアント(画面)からAjaxのリクエストを飛ばし、サーバー側で受けるので、受け口を先に作る…というわけです。ファイルの受け取りを行うので、とりあえず受信が出来ているか確認するものを作ります。

サンプル(クライアント)は下のリンクからアクセス出来ます。

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

でわでわ。。。


/*  https://developer.mozilla.org/ja/docs/DOM/XMLHttpRequest#sendAsBinary() */

if (!XMLHttpRequest.prototype.sendAsBinary) {
  XMLHttpRequest.prototype.sendAsBinary = function(sData) {
    var nBytes = sData.length, ui8Data = new Uint8Array(nBytes);
    for (var nIdx = 0; nIdx < nBytes; nIdx++) { ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff; } /* send as ArrayBufferView...: */ this.send(ui8Data); /* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */ }; } /* https://developer.mozilla.org/ja/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest * This framework is released under the GNU Public License, version 3 or later. * https://www.gnu.org/licenses/gpl-3.0-standalone.html * */ var AJAXSubmit = (function () { function ajaxSuccess () { /* console.log("AJAXSubmit - Success!"); */ console.log(this.responseText); /* you can get the serialized data through the "submittedData" custom property: */ /* console.log(JSON.stringify(this.submittedData)); */ } function submitData (oData) { /* the AJAX request... */ var oAjaxReq = new XMLHttpRequest(); oAjaxReq.submittedData = oData; oAjaxReq.onload = ajaxSuccess; if (oData.technique === 0) { /* method is GET */ oAjaxReq.open("get", oData.receiver.replace(/(?:\?.*)?$/, oData.segments.length > 0 ? "?" + oData.segments.join("&") : ""), true);
      oAjaxReq.send(null);
    } else {
      /* method is POST */
      oAjaxReq.open("post", oData.receiver, true);
      if (oData.technique === 3) {
        /* enctype is multipart/form-data */
        var sBoundary = "---------------------------" + Date.now().toString(16);
        oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary);
        oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" +
            oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n");
      } else {
        /* enctype is application/x-www-form-urlencoded or text/plain */
        oAjaxReq.setRequestHeader("Content-Type", oData.contentType);
        oAjaxReq.send(oData.segments.join(oData.technique === 2 ? "\r\n" : "&"));
      }
    }
  }

  function processStatus (oData) {
    if (oData.status > 0) { return; }
    /* the form is now totally serialized! do something before sending it to the server... */
    /* doSomething(oData); */
    /* console.log("AJAXSubmit - The form is now serialized. Submitting..."); */
    submitData (oData);
  }

  function pushSegment (oFREvt) {
    this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
    this.owner.status--;
    processStatus(this.owner);
  }

  function plainEscape (sText) {
    /* How should I treat a text/plain form encoding?
       What characters are not allowed? this is what I suppose...: */
    /* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" */
    return sText.replace(/[\s\=\\]/g, "\\$&");
  }

  function SubmitRequest (oTarget) {
    var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post";
    /* console.log("AJAXSubmit - Serializing form..."); */
    this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded";
    this.technique = bIsPost ?
        this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0;
    this.receiver = oTarget.action;
    this.status = 0;
    this.segments = [];
    var fFilter = this.technique === 2 ? plainEscape : escape;
    for (var nItem = 0; nItem < oTarget.elements.length; nItem++) { oField = oTarget.elements[nItem]; if (!oField.hasAttribute("name")) { continue; } sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT"; if (sFieldType === "FILE" && oField.files.length > 0) {
        if (this.technique === 3) {
          /* enctype is multipart/form-data */
          for (nFile = 0; nFile < oField.files.length; nFile++) {
            oFile = oField.files[nFile];
            oSegmReq = new FileReader();
            /* (custom properties:) */
            oSegmReq.segmentIdx = this.segments.length;
            oSegmReq.owner = this;
            /* (end of custom properties) */
            oSegmReq.onload = pushSegment;
            this.segments.push("Content-Disposition: form-data; name=\"" +
                oField.name + "\"; filename=\"" + oFile.name +
                "\"\r\nContent-Type: " + oFile.type + "\r\n\r\n");
            this.status++;
            oSegmReq.readAsBinaryString(oFile);
          }
        } else {
          /* enctype is application/x-www-form-urlencoded or text/plain or
             method is GET: files will not be sent! */
          for (nFile = 0; nFile < oField.files.length;
              this.segments.push(fFilter(oField.name) + "=" + fFilter(oField.files[nFile++].name)));
        }
      } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
        /* NOTE: this will submit _all_ submit buttons. Detecting the correct one is non-trivial. */
        /* field type is not FILE or is FILE but is empty */
        this.segments.push(
          this.technique === 3 ? /* enctype is multipart/form-data */
            "Content-Disposition: form-data; name=\"" + oField.name + "\"\r\n\r\n" + oField.value + "\r\n"
          : /* enctype is application/x-www-form-urlencoded or text/plain or method is GET */
            fFilter(oField.name) + "=" + fFilter(oField.value)
        );
      }
    }
    processStatus(this);
  }

  return function (oFormElement) {
    if (!oFormElement.action) { return; }
    new SubmitRequest(oFormElement);
  };

})();


Google Maps API 〜KMLファイルを作成するのはやめにしてJSON出力する〜

イントロダクション

前回、Google Maps APIを使用して地図を作成しました。
実装内容は以下になります。

  1. 画面をクリックするとピンが落ちてくる
  2. 選択場所の位置情報を画面に表示

KMLファイルを作る

参考サイトはこちらです。これを参考にしてKMLファイル(マップ情報を記載する)を作成するはずだったのですが、今回のやりたいこととずれているので、やめることにします。

JSONファイルを作る

KMLをやめにして、JSONファイルを作ることにします。経緯は以下のようになっています。

  1. KMLファイルは用途が違うのでやめ
  2. JSONファイルをサーバー上に設置して画面をロード(表示)するときにJSONを読み込む
  3. 地図上で選択、入力した情報をJSONファイルに出力するように実装する

このように処理内容を変更します。いわゆる「仕様変更」というものです。

JSONファイルの出力仕様

以下のような順序で処理を行う想定です。

  1. 地図の画面から登録する場所をタップ
  2. 選択した位置にオーバーレイが表示される
  3. 登録情報フォームに位置情報が表示される
  4. 登録する場所の名前とURL, 対象の写真を入力(選択)
  5. 登録ボタン(ラベル)を押下する
  6. PHPでそのデータをJSON形式でファイルに出力する

こんな感じで実装しようと思います。

技術的な話

今回の処理は2つに分かれます。

  1. クライアントサイド(HTMLとJS)、地図画面のこと
  2. PHPでのサーバーサイド処理、これはPHPでHTMLなどを出力しません。
  3. 送信される内容にテキスト、ファイルの2種類があるので、ファイルの取得(アップロードされたもの)を適当な場所に配置する or DBに登録する必要がある。

単純に画面からAjax(非同期通信)で対象のデータをサーバーに送信し次の処理を行ってしまいます。非同期なので送ってからレスポンスを待ちません。またその必要もありません。そのように設計したのもありますが。。。
なので、PHPではHTMLを出力するとか処理結果を返すことはさせません。この方が処理がスムーズかつ無駄が少ないからです。

実装に向けて

このように、仕組みを作る場合はシンプルにしたいものです。今回はうまく設計できたと思います(笑)。実装は以下の場所に随時実装していきます。

Github/ZenryokuService/LiveHouseMap

でわでわ。。。



Google Maps API 〜地図にオーバーレイを追加する〜

イントロダクション

前回、Google Maps APIを使用して地図を作成する準備を行いました。なんとか画面に地図を表示することができましたがこれだけでは面白くありません。。。

Google Mapにピンを追加

今回の本題です。作成したGoogle Mapにピン(オーバーレイ)を追加します。オーバーレイは
よく見るアレです。下の方にあります。

これは、自分の作成中の地図ですが「地図をクリックするとピンが表示される」という仕組みにしました。
意図するところは以下のような処理を考えております。

  1. 画面を選択する
  2. ピンが表示される
  3. 下の「名前」と書いてあるところに文字を入力
  4. 登録ボタンで位置情報をDBに登録する

以上のような処理を考えています。
現状の処理としては以下のようなイメージです。

  • HTMLでMapを作成する(JSの実装あり)
  • JSで細かい処理を行う

コード

参考にしたサイトは以下になります。

// 表示した地図にイベントを登録する
map.addListener('click', function(evt) {
   // イベント発生時の処理
   function (evt, map) {
// 緯度を設定する  document.getElementById('latValue').textContent = evt.latLng.lat();
// 経度を設定する document.getElementById('lngValue').textContent = evt.latLng.lng();
// オーバーレイを表示
selectedMarker = new google.maps.Marker(selectedOverlayOpt(evt));
    selectedMarker.setMap(map);
});

/** 選択用のオーバーレイOption */
function selectedOverlayOpt(mapEvent) {
    return {
        position: mapEvent.latLng,
        animation: google.maps.Animation.DROP,
        icon: {
            url: "mapImg/selected.png",
            scaledSize: new google.maps.Size(40, 40)
        },
    };


WebページにTwitterボタンを追加する方法

参考サイト:こちらのページを参考にしました。

ツイートボタンを追加する方法です。

  1. このツイッターボタン作成ページ?にアクセスします。
  2. キャプチャのように埋め込む(Embedする)ものを選択します。
  3. このボタンを押下して、埋め込むためのコードをコピー
  4. 自分のホームページ、ブログなどにコードをペースト

関連ページ

ツイッター開発者登録ページでツイッターAPIを登録する。










PHP コマンド実行 〜MacOSでphpコマンドを叩く(環境変数の設定と暗号化)〜

イントロダクション

TwitterAPIを使用するのに、ユーザー名とパスワードを使用します。しかし、このような情報はインターネット上に公開するとよろしくないので。。。

暗号化します

phpをテストするのに今まではウェブサーバー上でやっていましたが、ローカル(自分のパソコン上)で実行したい場合があります(今回のように)。なのでphpコマンドを実行する方法を記載します。

Macの場合はすでにコマンドが使用できるようです。しかし使えない場合にはどうしたら良いのか?自分の端末では再現できませんが、要点だけ。。。

早い話が、「php.exe」などの起動ファイルを環境変数に通せばOKです。環境変数とはシンプルに示すと以下のようになります。

REM Windowsの場合以下のコマンドで表示される
>path

# Macの場合は以下のコマンドで表示される
$ echo $PATH

このコマンドで表示される、パスが環境変数に設定がされている状態です。

とりあえず、Windowsの場合は、php.exeがあるフォルダを環境変数に加えればOKです。 Macの場合はHome brewを使用するようです。詳細は本家サイトを参照ください。

PHPコマンドで暗号化

今回はJavaを使いたいのでJarファイルを作成してPHPコマンンドでjarを実行してみます。

この動画では「Hello Java」を出力しているだけですが、Javaの処理を変えてやれば「Java呼び出し」はできているのでphpから起動できることの証明になります。

ちなみにphpでjavaを起動した時は環境変数などが読み込まれていないのでパスをそのまま実装します。

そして実行したコマンドは以下の通りです。

JDKへのパス/bin/java -jar 起動するJARファイル

<実行結果>

------- output ------------array(1) {
  [0]=>
  string(10) "Hello Java"
}

純粋なJavaの起動する方法はJavaBasic〜Hello World〜を参照ください。

そして、phpから起動するときに暗号化したパスワードを下のようにプログラム引数に渡します。

java -jar Cription.jar 暗号化したパスワード

phpのコードは以下のようになります。

<?php
$result = null;
$output = null;
exec('/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -jar Cryption.jar 暗号化したパスワード 0123456789012345', $output, $result);

print("------- output ------------");
var_dump($output);
print("-------- result -----------");
var_dump($result);
?>

実行結果

php test.php # コマンドの実行
------- output ------------array(4) {
  [0]=>
  string(54) "プログラム引数:暗号化したパスワード"
  [1]=>
ڀ}"ng(33) "暗号化:
  [2]=>
  string(40) ".Jpą!"
  [3]=>
  string(45) "復号号化:暗号化したパスワード"
}
-------- result -----------int(0)

とシンプルな感じです。

Javaのコードに関してはGitにあげてあります。

実際にテスト

作成したJARファイルをサーバーにアップします。URLは下に示します。

Githookのリクエストパラメータを取得します。

とりあえずテストします。

GitのWebhookからリクエストを受けて、リクエストの内容を出力して見ました。ファイルのパーミッション(権限)の部分で手こずりましたが、何とか。。。

下のようなコード(PHP)でログを取得しました。

 // Gitから(Webhookで)送信されたJSON
 $json_string = file_get_contents('php://input');
 // 送信されたJSONを読める形に変換する
 $json = json_decode($json_string,true);
 $fileName = chmod('githookLog.txt', 0666);
 $outData;
 foreach ($json as $key => $value) {
 $outData =$outData . "Key: " . $key . " / Value: " . $value;
 }
 file_put_contents('githookLog.txt', '--JSON:' . $_SERVER['REMOTE


悲報

レンタルサーバー上ではコマンドでjavaの実行ができませんでした。。。。

<実行手順>

  1. JDKの中身をサーバー上にアップロード
  2. PHPからexec関数を実行
    exec('../java/bin/java -jar Cryption.jar 暗号化したパスワード 0123456789012345', $output, $result);