PHP 2016年08月22日 12:20 編集
日付のログを残す必要がある場合、あまり考えずにtime()関数で得られるエポック秒をそのまま保存していたが、エポック秒は2038年問題を起こすらしい。
2038年にならなくてもエポック秒同士の計算をしてその結果が最大値2147483647を超えるとエラーを起こすことになる。最大値を超えるとマイナスになってしまうというケースもあるようだが、Xamppを使用したローカル環境でテストしてみると、最大値を超えるとintegerではなくfloat値と判断され、エポック秒を使う関数では、float値を想定していないのでエラーになる。
とりあえず、time()を使っている部分はdate_createやDateTimeを使って書き換えたが、setcookie関数にもエポック秒を渡すことになっているのが面倒。
指定しなければ、ブラウザを閉じるまで有効なクッキーということになるらしいが、それではクッキーの意味が無い。
このようにエポック秒でしか得られないもの、指定できないものもあるようなので、完全にエポック秒を使わないというのは難しそうだ。エポック秒を64bit整数値で扱うようになれば、最大値が桁違いに増えるため実質的に問題はなくなりそうだ。32bitのままでも符号付きから符号なし整数値で処理できれば、扱える年数が数十年延びる。おとなしくPHPの仕様の変更を待つ方がいいかも知れない。
今のところ注意すべきは日付の足し算をする場合、エポック秒のままで計算すると上限を超えてしまうおそれがあるということだ。たとえば2016年の25年後を計算したら超えてしまう。引き算も結果が1970年以前になるとエラーになる。このため、こうした計算をする場合はdate_createやDateTimeを使ってtimeオブジェクトを生成した方がいい。
2038年問題
エポック秒とは1970年1月1日午前0時0分0秒からの経過秒のことで、1秒ごとに1増えている。そしてこのエポック秒は符号付き整数値という形式になっているが、この符号付き整数値の最大値が2147483647で、2038年1月19日午前3時14分8秒にこれを超えてしまう。2038年にならなくてもエポック秒同士の計算をしてその結果が最大値2147483647を超えるとエラーを起こすことになる。最大値を超えるとマイナスになってしまうというケースもあるようだが、Xamppを使用したローカル環境でテストしてみると、最大値を超えるとintegerではなくfloat値と判断され、エポック秒を使う関数では、float値を想定していないのでエラーになる。
日付フォーマット
エポック秒のままログに保存するのはやめた方が良さそうだが、すでに保存されているログをすべて修正するのも面倒だ。時間ログとして保存されている数値が符号付き整数値になっている場合は、エポック値として処理し、そうでない場合は新しいフォーマットとして処理することにする。とりあえず、time()を使っている部分はdate_createやDateTimeを使って書き換えたが、setcookie関数にもエポック秒を渡すことになっているのが面倒。
指定しなければ、ブラウザを閉じるまで有効なクッキーということになるらしいが、それではクッキーの意味が無い。
このようにエポック秒でしか得られないもの、指定できないものもあるようなので、完全にエポック秒を使わないというのは難しそうだ。エポック秒を64bit整数値で扱うようになれば、最大値が桁違いに増えるため実質的に問題はなくなりそうだ。32bitのままでも符号付きから符号なし整数値で処理できれば、扱える年数が数十年延びる。おとなしくPHPの仕様の変更を待つ方がいいかも知れない。
今のところ注意すべきは日付の足し算をする場合、エポック秒のままで計算すると上限を超えてしまうおそれがあるということだ。たとえば2016年の25年後を計算したら超えてしまう。引き算も結果が1970年以前になるとエラーになる。このため、こうした計算をする場合はdate_createやDateTimeを使ってtimeオブジェクトを生成した方がいい。
counter:5,126
PHP 2016年08月22日 12:20 編集
ソート
-
連想配列の値でソート
asort($array); // 昇順
arsort($array); // 降順
-
連想配列のキーでソート
ksort($array); // 昇順
krsort($array); // 降順
-
シュウォーツ変換風ソート
my @keys = (keys %count);phpだと、前準備が必要だが
@keys = map {$_->[0]} sort {$a->[3] <=> $b->[3]} map {[$_, split /_/]} @keys;
$keys = array_keys($counts);のような感じ
$sort = array();
foreach ($keys as $i) {
$tmp = explode('_',$i);
$sort []= $tmp[3];
}
array_multisort($sort,SORT_ASC,SORT_NUMERIC,$keys);
サクラエディタでphpに変換
pp(****) → "****"qq\((.+?)\)ハッシュを連想配列に変更
"$1"
$hash{'***'} → $hash['***']
(\$[^$!(){]+?)\{(.+?)\}文字列中の配列の表記を変更
$1[$2]
mode=$in['graph_mode']& → mode=" . $in['graph_mode'] . "&
=(\$in\[.+?\])正規表現の表記を変更
=" . $1 . "
$str =~ /$ptn/ → preg_match('/$ptn/',$str)
(\$.+) =~ (\/.+\/)
preg_match('$2',$1)
counter:4,571
PHP Perl 2016年12月21日 14:36 編集
perlで書いていたCGIを、PHPしか動かないサーバーで使う必要に迫られ、PHPに書き換えた。その際の注意すべき点をまとめた。
また、perlでは、変数のタイプが違うと、同じ名前をつけることができる。たとえば、$data、@data、%dataを同時に別の変数として扱える。PHPではこれはできないので、perlからPHPへの移行の際には、まずこれに注意が必要だ。
変数
perlの場合は、変数のタイプによって頭につける文字が違う。スカラー変数は$、配列は@、ハッシュは%というように。一方PHPの場合は、すべて$をつけることになるので、一見しただけでは変数に何が保存されているのかわかりにくいという問題がある。また、perlでは、変数のタイプが違うと、同じ名前をつけることができる。たとえば、$data、@data、%dataを同時に別の変数として扱える。PHPではこれはできないので、perlからPHPへの移行の際には、まずこれに注意が必要だ。
counter:6,652
PHP Shade 2021年06月19日 02:29 編集
Shadeプラグイン・スクリプト検索もレスポンシブ対応にしようかなと思って、久しぶりにCGIファイルを見てみたら、いろいろ他にも気になる部分が目について、結局ゼロからPHPで書き直すことにした。ちょこちょこ修正しているとはいえ、元はなんせ20年も前に書いたものだからなー。
スムーズに移行できるようログは旧CGIで作成したものをそのまま流用するつもりだったが、データを1個のファイルにすべて保存する形式にしていたのがどうも気になる。ダウンロードカウントもこのファイルに書き込む方式だったので、アクセスがあるたびにデータファイルを書き換える処理をしていたことになる。最初のころしょっちゅうログファイルが壊れていたのはこれが原因だったのかもしれない。
さすがにこれはないだろうと、まず新しいPHPプログラムでアクセスすると旧データファイルを扱いやすいデータ形式に書き換えることにする。登録内容1件ごとにファイルを作成することにして、ダウンロードは別ファイルでカウントすることにする。新方式のデータファイルを作成したら旧データファイルにはアクセスしないことにした。
スムーズに移行できるようログは旧CGIで作成したものをそのまま流用するつもりだったが、データを1個のファイルにすべて保存する形式にしていたのがどうも気になる。ダウンロードカウントもこのファイルに書き込む方式だったので、アクセスがあるたびにデータファイルを書き換える処理をしていたことになる。最初のころしょっちゅうログファイルが壊れていたのはこれが原因だったのかもしれない。
さすがにこれはないだろうと、まず新しいPHPプログラムでアクセスすると旧データファイルを扱いやすいデータ形式に書き換えることにする。登録内容1件ごとにファイルを作成することにして、ダウンロードは別ファイルでカウントすることにする。新方式のデータファイルを作成したら旧データファイルにはアクセスしないことにした。
counter:2,491
Xampp PHP 2019年11月16日 14:07 編集
いつのまにかXamppの64bit版がでていた。というか64bitに変更されたのかな。
同梱のPHPも64bitになっているようで、これで2038年問題も解消されたようだ。(PHPの時間ログについて参照) 32bit版ではエラーになっていた
これはローカルだけの問題でWEBサーバーの方はとっくに64bitになっていたのかもしれない。ここのサーバーのPHPも64bitになっているようだ。
同梱のPHPも64bitになっているようで、これで2038年問題も解消されたようだ。(PHPの時間ログについて参照) 32bit版ではエラーになっていた
$epoc_sec = 2147483648;も問題なく実行できる。
echo date("Y/m/d H:i:s",$epoc_sec);
これはローカルだけの問題でWEBサーバーの方はとっくに64bitになっていたのかもしれない。ここのサーバーのPHPも64bitになっているようだ。
counter:3,553
PHP 迷惑投稿対策 2020年03月25日 19:58 編集
Kent-Webのサポート掲示板で教えてもらったjQueryのslidelockというスパム対策機能を、この用語集作成PHPのbbsプラグインで使えるようにしてみました。→PHP/用語集作成
counter:9,398
PHP 2016年08月22日 12:19 編集
ローカル環境で、PHPで表示したHTMLからPDFを出力するためにmpdfモジュールを使用しているが、「﨑」、「髙」など特定の文字が文字化けしてしまう。
それを回避するためのメモ。
まずhttp://www.mpdf1.com/mpdf/index.php?page=Downloadから最新版のmpdfをダウンロード。
xamppにPHPのモジュールとしてインストールすることも出来るが、webサーバーにはmpdfがインストールされてない場合もあるので、
そういう場合でも使用できるよう、ほかのPHPファイルなどと同様にhtdocs内に保存した。
mpdfを使用するPHPで使用する前にmpdfをインクルードして使用することになる。
たとえば、実行するPHPファイルと同じディレクトリ内に./includeディレクトリを作り、その中にmpdfを入れた場合、以下のような関数でmpdfが利用できる。
となる。
それを回避するためのメモ。
まずhttp://www.mpdf1.com/mpdf/index.php?page=Downloadから最新版のmpdfをダウンロード。
xamppにPHPのモジュールとしてインストールすることも出来るが、webサーバーにはmpdfがインストールされてない場合もあるので、
そういう場合でも使用できるよう、ほかのPHPファイルなどと同様にhtdocs内に保存した。
mpdfを使用するPHPで使用する前にmpdfをインクルードして使用することになる。
たとえば、実行するPHPファイルと同じディレクトリ内に./includeディレクトリを作り、その中にmpdfを入れた場合、以下のような関数でmpdfが利用できる。
function mpdf_preview($url,$file) {
require_once('./include/mpdf/mpdf.php'); // ①mpdf.phpを読み込む
$html = file_get_contents($url); // ②URLが$urlのhtmlの内容を取得する。
$html = mb_convert_encoding($html,"SJIS-win","EUC-JP");
// ③なぜかEUC-JPからUTF-8に直接変換すると「﨑」などが文字化けするので、いったんSJIS-winに変換する。
$html = mb_convert_encoding($html,"UTF-8","SJIS-win");
// ④mpdfを使う前にUTF-8に変換しておかないとエラーが出る場合があるので、UTF-8に変換する。
$mpdf = new mpdf('ja+aCJK');
$mpdf->WriteHTML($html);
if ($file) {
$mpdf->Output($file,'F'); // ⑦ファイル名$fileを指定してPDFファイルを保存する。
} else {
$mpdf->Output(); // ⑧$fileを指定しない場合は、ブラウザに表示するのみ
}
}
となる。
- まず、①でmpdfが使えるように mpdf.php を読み込む。
- file_get_contents($url) で、$url(フルパス)で表示されるhtmlの文字列を取得して$htmlに保存する。
- その文字列$htmlをmpdfに渡してPDFに変換するわけだが、そのまま渡すとエラーになる場合があるので、$htmlはUTF-8に変換する必要がある。
mb_convert_encodingで文字コードを変換する。
PHPをEUC-JPで書いている場合、$html = mb_convert_encoding($html,"UTF-8","EUC-JP");
としたくなるが、こうすると例の「﨑」とか「髙」が文字化けする。
PHPをSJISで書いている場合は$html = mb_convert_encoding($html,"UTF-8","SJIS");
としたくなるが、これも﨑」、「髙」が文字化けする。
これは$html = mb_convert_encoding($html,"UTF-8","SJIS-win");
としなければならないらしい。EUC-JPも文字化けしない指定名があればいいのだが、わからなかったので、EUC-JPの場合は、$html = mb_convert_encoding($html,"SJIS-win","EUC-JP");
のように、いったんSJIS-winに変換して2段階でUTF-8に変換すると、文字化けを解消できた。
$html = mb_convert_encoding($html,"UTF-8","SJIS-win");
counter:6,283
PHP 迷惑投稿対策 2021年06月30日 19:54 編集
スパム投稿対策研究のために設置した掲示板を長いこと放置していたら、スパム投稿でひどいことになっていた。対策は継続してやらないとダメのようだ。
旧掲示板のURLから今回新たに公開したbbs.phpにリダイレクトするようにした。PHP/掲示板PHP
・・・と思っていたが掲示板2の方はさっそく前の掲示板と同じ傾向のスパム投稿が来ている。JavaScriptのスライドロックも効果が無いので、ひょっとしたら人が投稿している?
bbs.phpのスライドロックは、ロボットはJavaScriptは無視するらしいということに期待して、JavaScriptで表示するロックを外さないと投稿できないという仕組みだ。ボタンを横にスライドするだけなので、読みにくい文字を入力したり、写真を選ぶ必要はない。この記事のテーマであるユーザーの負担が少ないスパム投稿対策というわけだ。
旧掲示板のURLから今回新たに公開したbbs.phpにリダイレクトするようにした。PHP/掲示板PHP
- ./yybbs/yybbs.cgi → ./yybbs/bbs/bbs.php
- ./clip/clip.cgi → ./clip/bbs/bbs.php
・・・と思っていたが掲示板2の方はさっそく前の掲示板と同じ傾向のスパム投稿が来ている。JavaScriptのスライドロックも効果が無いので、ひょっとしたら人が投稿している?
bbs.phpのスライドロックは、ロボットはJavaScriptは無視するらしいということに期待して、JavaScriptで表示するロックを外さないと投稿できないという仕組みだ。ボタンを横にスライドするだけなので、読みにくい文字を入力したり、写真を選ぶ必要はない。この記事のテーマであるユーザーの負担が少ないスパム投稿対策というわけだ。
counter:5,201
PHP 2021年04月26日 11:52 編集
長過ぎる文字列を切り詰めて短くしたいことがよくあるので、指定した文字数以上の文字は指定数に切り詰めて省略記号をつけるという処理のために以下のような関数を使っていましたが、思うように動かないことが多々ありました。
function jtruncate($str,$n) {たとえばこの関数を使って
if ($n < 2) { return ; }
if (strlen($str) <= $n) { return $str ; }
$substr = mb_substr($str,0,intval($n/2),"UTF-8") . '...';
return $substr;
}
print jtruncate('PHPのコード',14);を実行すると
PHPのコード...と切り詰めていないはずなのに切り詰めた記号...が表示されてしまいます。
counter:3,853