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,779
PHP 迷惑投稿対策 2020年03月25日 19:58 編集
Kent-Webのサポート掲示板で教えてもらったjQueryのslidelockというスパム対策機能を、この用語集作成PHPのbbsプラグインで使えるようにしてみました。→PHP/用語集作成
counter:9,300
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,467
PHP 2018年05月25日 16:37 編集
ローカルPCにインストールしているXamppをアップデートしてPHPのバージョンがPHP7.2.5になったらあちこちで警告が出るようになりました。
create_functionを使わず、ネイティブの無名関数を使ったほうがいいということです。具体的には
$attr['ID']がsetされてなかったら、''を代入するという処理です。$attrが未定義の場合も問題ないはずでなぜエラーになるかわかりませんでしたが、調べてみると$attrの型がstringになっている場合もあって、その状態で実行するとエラーになっているようです。エラーを回避するためにとりあえず上記の式の前に
'0.84479900 1527156353'
のような文字列を返しています。PHP7.1ではこの文字列のまま計算しても適当にfloatに変換してくれていましたが、7.2では警告が出るようになりました。microtime(True)を指定するとfloatを返しますが、小数点以下の桁数が減るので、文字列のままにした方がより精度の高いマイクロ秒が得られます。文字列は小数部分と整数部分をスペースで区切っているので、小数部分だけを抽出するために
バージョン7.2では、型について厳格になったようです。別の型ということになっているのにその型ではできない処理をしようとしたら、前のバージョンではその処理が行える型に変更したりする部分もあったが7.2以降ではエラーや警告を出すということになっているようです。
create_function()は非推奨
まず、create_function関数が非推奨になったためにその警告が出ます。create_functionを使わず、ネイティブの無名関数を使ったほうがいいということです。具体的には
create_function( '$a,$b', 'return strlen( $b ) - strlen( $a );' )は
function($a,$b) { return strlen( $b ) - strlen( $a ); }に変えます。
each()も非推奨
このほかeach()関数も非推奨になっています。mpdfモジュールでwhile(list($file,$info)=each($this->images)) {という部分で警告が出ているので、
foreach ($this->images as $file=>$info) {と変更すると警告は出なくなりました。
非配列に要素を追加すると警告
mpdfモジュール関係ではcssmgr.pdfでif (!isset($attr['ID'])) { $attr['ID']=''; }のような行でも警告が出るようになりました。
$attr['ID']がsetされてなかったら、''を代入するという処理です。$attrが未定義の場合も問題ないはずでなぜエラーになるかわかりませんでしたが、調べてみると$attrの型がstringになっている場合もあって、その状態で実行するとエラーになっているようです。エラーを回避するためにとりあえず上記の式の前に
if (isset($attr) && !is_array($attr)) { $attr = array(); }を追加するとなんとかエラーが出なくなりました。
文字列の計算をすると警告
$tm1 = microtime();を実行すると警告が出るようになりました。microtime()は、現在の Unix タイムスタンプをマイクロ秒単位で返す関数ですが、デフォルトではfloatではなく、
$tm2 = microtime();
echo $tm1 - $tm2;
'0.84479900 1527156353'
のような文字列を返しています。PHP7.1ではこの文字列のまま計算しても適当にfloatに変換してくれていましたが、7.2では警告が出るようになりました。microtime(True)を指定するとfloatを返しますが、小数点以下の桁数が減るので、文字列のままにした方がより精度の高いマイクロ秒が得られます。文字列は小数部分と整数部分をスペースで区切っているので、小数部分だけを抽出するために
list($tm1) = explode(' ',microtime());のように変更すると警告は出なくなりました。
list($tm2) = explode(' ',microtime());
echo $tm1 - $tm2;
配列の追加
キーが数値の配列に追加する場合はarray_push('abc')とするより
$array[] = 'abc';の方が速いらしいということで、もっぱら下を使っていますが、追加する変数の型が配列になっていないとエラーが出るようになりました。たとえば
$array = '';はエラーになるので、$arrayの型がarray以外になっている可能性がある場合は、
$array[] = 'abc';
unset($array)あるいは
$array = array();と初期化しておく必要があります。これは[]を使って配列を追加する場合だけでなく、配列型になっていない変数を配列として扱おうとすると、同じようなことが起こると思われます。
バージョン7.2では、型について厳格になったようです。別の型ということになっているのにその型ではできない処理をしようとしたら、前のバージョンではその処理が行える型に変更したりする部分もあったが7.2以降ではエラーや警告を出すということになっているようです。
counter:4,795
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,586
PHP 暗号 2016年08月22日 12:20 編集
パスワードをハッシュ化する場合、perlでは、crypt関数を使うと有効な文字列が8文字までという制限が有るため、MD5モジュールを使ってハッシュ化していたが、PHPの場合は逆にcryptを使った方が強度は高いようだ。
ハッシュ化の目的は、サーバー上に保存したパスワードが万一漏洩しても、元のパスワードが知られないようにするためで、この場合復号する必要は無い。ハッシュ化されたパスワードと元のパスワードを照合して、ハッシュ化されたものが元のパスワードから生成されたものであることがわかりさえすればいい。
PHPでmd5()関数を使うと、ハッシュ値と呼ばれる32桁の16進数に変換される。
「abcd」とハッシュ化された文字列は1対1の対応で、「abcd」を何度md5でハッシュ化しても「e2fc714c4727ee9395f324cd2e7f331f」になる。
このハッシュ値から元の文字列を得る方法はない。つまり「e2fc714c4727ee9395f324cd2e7f331f」から元の「abcd」を得ることはできないということが、秘匿性を守る根拠になっている。
ところが、ハッシュ値のデータベースから元の値を得るモジュールなるものが存在するらしい。
ハッシュ化の目的は、サーバー上に保存したパスワードが万一漏洩しても、元のパスワードが知られないようにするためで、この場合復号する必要は無い。ハッシュ化されたパスワードと元のパスワードを照合して、ハッシュ化されたものが元のパスワードから生成されたものであることがわかりさえすればいい。
PHPでmd5()関数を使うと、ハッシュ値と呼ばれる32桁の16進数に変換される。
$str = 'abcd';実行結果
$md5 = md5($str);
echo $md5;
e2fc714c4727ee9395f324cd2e7f331fたとえば上記のように「abcd」という文字列をmd5でハッシュ化すると、「e2fc714c4727ee9395f324cd2e7f331f」という文字列が得られる。
「abcd」とハッシュ化された文字列は1対1の対応で、「abcd」を何度md5でハッシュ化しても「e2fc714c4727ee9395f324cd2e7f331f」になる。
このハッシュ値から元の文字列を得る方法はない。つまり「e2fc714c4727ee9395f324cd2e7f331f」から元の「abcd」を得ることはできないということが、秘匿性を守る根拠になっている。
ところが、ハッシュ値のデータベースから元の値を得るモジュールなるものが存在するらしい。
counter:6,357
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,100
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,557
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,239