Google Map API で地名から緯度経度を取得する
PHPで実行時間を同時に何箇所も計測する
function setBenchMarker() { if ( !is_array($GLOBALS["benchmark"]) ) { $GLOBALS["benchmark"] = array(); } $trace = debug_backtrace(); $line = $trace[0]["line"]; $file = $trace[0]["file"]; array_push($GLOBALS["benchmark"], array("point"=>$file.":".$line, "time"=>microtime(true))); } function getBenchMarkResult($delim="\n") { $lasttime = 0; $lastpoint = 0; $retbuf = ""; $records = $GLOBALS["benchmark"]; foreach ( $records as $record ) { $point = $record["point"]; $time = $record["time"]; if ( $lasttime != 0 ) { $retbuf .= "[".$lastpoint."]--[".$point."] = ".sprintf('%0.5f', $time-$lasttime).$delim; } $lastpoint = $point; $lasttime = $time; } return $retbuf; }
使い方
class Hoge { public function __construct( ){} public function moge() { setBenchMarker(); } } function foo() { setBenchMarker(); } setBenchMarker(); foo(); $hoge = new Hoge(); $hoge->moge(); setBenchMarker(); $bench = getBenchMarkResult(); echo $bench;最終結果を文字列として返しているのはerror_logなどに出力することもあるだろうなので、 中でechoはしないようにしている。
実行結果例
$ ./test.php [/home/ec2-user/test/test.php:4]--[/home/ec2-user/test/test.php:21] = 0.087116003 [/home/ec2-user/test/test.php:21]--[/home/ec2-user/test/test.php:30] = 0.010456085 [/home/ec2-user/test/test.php:30]--[/home/ec2-user/test/test.php:9] = 0.000001907
人間を宇宙に送り出す必要性
宇宙服のこれまでとこれから。
paypal月額課金のIPN Listenerの実装
Paypal上にこのIPNの仕様のドキュメントはあるはあるのだが、ドキュメントがあまり更新されてなかったり、リンク切れのドキュメントがあったりと、やれやれな状態だが、実装した方法を紹介。
定期購読とIPNのおおまかな流れ
- ユーザが設置した定期購読ボタンを押下する
- Paypalに遷移し、ユーザがPaypal上で決済を行う
- Paypal上の決済完了画面が表示される(自サービスのページには戻されない)
- 非同期でPaypalから自サーバのIPN ListenerのAPIがコールされ、トランザクションを受け取る(トランザクションの種類については後述)
- 自前のIPN Listenerでは、受けたトランザクションがPaypalからのものであるかどうかを確認するためにPaypalに確認のコールを行う
- 妥当性の確認が取れたらユーザの決済が完了したトランザクションを確認したらユーザに課金のサービスを提供できる状態にする(DBの更新とか)
- 定期的(ボタンで設定した決済間隔)にユーザの決済処理が行われて、その結果がトランザクションで飛んで来るので、決済されていればサービス延長する。
- 定期購読の契約がキャンセルされたら同じくキャンセルのトランザクションが飛んでくるので当該サービスを停止処理を行う。
定期購読ボタン作成時の注意
- ボタンを作成する際には提供サービスごとに課金額を変えるような場合は、購読IDを指定するか、カスタム値にサービスのIDを入れる。
- また、Paypalからのトランザクションの戻りがどのユーザの決済かを判断するためにカスタム値にユーザIDなどを入れておく。
サービスIDとユーザIDをボタンのカスタム値としていれる例
<input TYPE="hidden" name="custom" value="<?php echo $serviceid;?>,<?php echo $userid">※何個もカスタム値を入れるなら、わかりやすくするために、serviceid=1,userid=hoge のような入れ方のほうが良いかも。
IPNトランザクションの種類
subscr_signup(購読の契約が行われた)
subscr_payment(決済が行われた)
subscr_cancel(購読の契約が解除された)
subscr_failed(決済が失敗した)
クレジットカードの有効期限が切れていたりなどで、決済日に決済が行われないとこのトランザクションが流れてくる。こいつがくせ者で、決済に失敗したからといって購読の契約が解除されたわけではない。提供サービスを停止して、再度、定期購読が申し込める画面にアクセスできるようにしてしまうと、ユーザが2重の契約をしてしまう可能性がある。
クレジットカードを登録しなおしたりで決済が可能になると、subscr_paymentが流れてくるので、failed中はサービスを停止ではなくサスペンド状態という扱いにするなどして、契約がキャンセルされたわけじゃないということを意識しておく必要がある。
subscr_failの状態がどれだけ続いたとしても契約は残っている。契約が解除されたら、必ずsubscr_cancelが流れてくるのでそれまではサスペンドする。
subscr_eot(購読の有効期限切れ)
StackOverflowでは、以下の様なことやり取りしているが、うーん、わからん。
TLS1.2対応が必須になりそう
どうもPHP5.3のcurlではTLS1.2のプロトコルに対応していないようなので、サーバのcurlコマンドをアップデートして、exec関数でコールするようにしてみた。
Paypalから受け取ったデータの妥当性のチェック通信を行なう
function confirmPaypalTransaction($posts) { $paypal_domain = "www.paypal.com"; //テスト環境はsandbox.paypal.com $req = 'cmd=_notify-validate'; foreach ($posts as $key => $value) { $value = urlencode(stripslashes($value)); $req .= "&".$key."=".$value; } $url = 'https://'.$paypal_domain.'/cgi-bin/webscr'; $cmd = '/usr/bin/curl '.$url.' --tlsv1.2 -d "'.$req.'"'; exec($cmd, $res, $ret); /* 以下のcurl関数では叩けなくなった(PHP5.3) $ch = curl_init($url); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'rsa_aes_128_sha'); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close')); if ( !$res = curl_exec($ch) ) { $this->writeLog("FATAL", "CURL ERROR:". curl_error($ch)); } curl_close($ch);*/ return $res; }
FileZillaがアップデートの度に調子悪くなるのでバージョンを戻す
MacでFTPやSCPをするためにFileZillaを使っている。
頻繁にアップデートがあるのだが、起動のたびにアップデートのダイアログが表示され、非表示に設定できない。
しかも、ご丁寧なことに置き換えアップデート用のファイルをDocumentsディレクトリ以下に勝手にダウンロードして置いていく。
設定画面の「Updates」で自動更新を「Never」にしてもファイルは勝手にダウンロードするし、新しいバージョンが有るダイアログは非表示にならない。
あまりに起動時のダイアログがうざったいので、観念してインストールすると、
だいたい、使い勝手が悪くなっていく。
以前のバージョンからの問題点
前回アップデートした時は、サーバへの新規ファイルのSCPアップロードをすると、
ファイルパーミッションが権限なし(000)でアップロードされた。
今回、3.15.0.1にアップデートをすると、接続するサーバの一覧を選ぶ「サイトマネージャ」の
サーバリストのスクロールがめちゃくちゃ反応が悪くなっている。(スクロールしてから0.5秒ぐらいのdelay)
大した話じゃないとはいえ、毎日何度も使うものなので細かなストレスが積み上がるのだ。
FileZillaのバージョンを戻す
手前はタダで使わせてもらっている分際でございますので、文句ばっかり言ってないで、
バージョンを戻してみることに。
https://osdn.jp/projects/filezilla/releases/
その他全ファイル > FileZilla_Client からバージョンを選んでダウンロードできる。
とはいえ、以前快調だった時のバージョンなんて覚えていないわけであります。
仕方ないので、リリースノートを見ながら、致命的なバグが無いところまで遡ってい行く。
https://filezilla-project.org/versions.php
見た感じ、3.12.0.2あたりがよさ気なので、ダウンロードしてアプリの入れ替え。
再インストール後の動作の確認
Detected newer version of FileZilla
The file '/Users/XXXXX/.filezilla/sitemanager.xml' has been created by a more recent version of FileZilla.
Loading files created by newer versions can result in loss of data.
Do you want to continue?
というダイアログが出てくる。
どうもxmlの構造が新バージョン用になってしまっているようだ。
とりあえず、「はい」ボタンを押す前に、
/Users/XXXXX/.filezilla/sitemanager.xml
のファイルをバックアップしておく。(XXXXXはユーザ名)
「はい」ボタンを押して、サイトマネージャを起動。
とりあえず、ファイルパーミッションの問題が一番キツイので、
サーバにファイルをアップロードしてファイルがパーミッション644になっていることを確認した。
「Detected newer version of FileZilla」のダイアログは2,3回出てきたが、そのうち出てこなくなった。
ただ、やはり「新しいバージョンダウンロードしておいたよ!」のダイアログは消せず。
とりあえず、しばらくこれで使ってみて具合が悪ければ、また別のバージョンを試してみる。
JavaScriptで月日を2桁表示にするスマートな方法
JavaScriptのDateオブジェクトのgetDateやgetMonthで月日を取得すると、0〜9の時は、0埋めされ無いデータになってしまう。
UnixtimeをDateの型に変換するツールを作った時に困ったので調べてみた。
0埋めのスマートな実装
桁数のlengthをチェックして0埋めしてという関数を準備してもいいのだが、1桁だろうと2桁だろうと頭に0を付けて2桁にしてしまうという方法がとてもスマートだ。
//月 var month = ("0"+(date.getMonth() + 1)).slice(-2), //日 var date = ("0"+date.getDate()).slice(-2)
参考にしたページ
・JavaScriptで日付や時間の0詰めを実装する
http://tagamidaiki.com/javascript-0-chink/