POTI-boardのレス先検索

$fp = fopen("hoge/tree.log", "r"); //ログファイルの場所
while ($line = fgets($fp)) {
//ログファイルの書式から変数を取得
$tree = explode(",", $line);//コンマ区切り形式のログの解析
$i=0;
$a=mb_substr_count("$line", ",")+1; //レスの数
//コンマ区切りなのでコンマの数+1。
while ($i < $a) {//0からレスの数までループ
if(rtrim($tree[$i], "\n")==$resno){
$resno=rtrim($tree[0], "\n");//スレッドの番号は$tree[0]
$count_end=true;//カウント終了
break;
}
if($count_end){break;}//レス先が見つかったのでbreak
echo "$i</br>";//確認用、実際には使わない。
$i++;
}
}
fclose($fp);
↑過去の自分が書いたコード。
$find=false:
$fp = fopen('hoge/tree.log', "r");
while($line=fgets($fp,4096)){
$treenos=explode(",",rtrim($line));
foreach($treenos as $treeno){
if($treeno===$no){
$resno=$treenos[0];
$find=true;
break;
}
}
if($find){
break;
}
}
fclose($fp);
↑今ならこう書きます。
配列がまったく理解できていなかった事がよくわかります…。

お絵かき掲示板はこちら。

POTI-boardのforをforeachに書き直し

forで配列の反復をしているところがたくさんあったので、foreachに書き直し。
配列のcountをしてそれから…では可読性が落ちる。
配列の書き直しなら参照渡しを使えばシンプルにまとめる事ができる。キーを取得しなくてもいいのでスマート…。
と思ったら…。
PHPの繰り返し処理大全 - Qiita

foreachでリファレンスが取れますが、使用してはいけません。
そもそもリファレンスはあらゆる場面で一切使用禁止です。
PHPのforeachで参照渡しをしたいときに気をつけること - Qiita

参照渡しはどうしても必要じゃないとき以外は使用しない方が良さそうです。
配列の書き直しに参照渡しを使っていたのですが、かなり強い口調で使ってはいけない…。

それならキーを取得して配列を書き直し…と思ったのですが…。
バグりました…。

問題なく動いているのにこの作業を行う事でバグを作ったらどうにもならないので、foreachで参照渡しを使ったらを忘れずにunset($value)すれば…。

と思ったら何箇所か抜けていました。

Bracket Pair Colorizer - Visual Studio MarketplaceをインストールしたVScodeで確認してみたら…。
ループの中でunset()している箇所が見つかったり…。

foreach 参照渡し php

インデントの位置がおかしいですが…。少し前のコードです。
foreachを使っていますが参照渡しは使っていません。

foreach 参照渡し php

参照渡しを使って配列を書き換えるコード。

$line[$i]と$valueがごちゃごちゃ入るより、参照渡しにして$valueだけにしてしまったほうがコードが見やすくなるような気もするんですけどね…。

参照渡しのforeachを使っているのにunset($value)が無い、もしくは位置がおかしいのはまずいので修正しました。
その事でトラブルが起きた…という事例は無いようなのですが…。

この修正はPOTI-board改 v1.53.6 lot.190926に反映されました。

お絵かき掲示板はこちら。

GitKrakenの代わりになるGUIのGitクライアント

GitKrakenの無料版では非公開リポジトリを開けなくなりました。
サブスクリプションで年額$49…いや$29?
いずれにしても無料版では非公開リポジトリを開く事ができくなってしまったので他のGitクライアントを探す事にしました。

基本は…たしかGit for Windowsだよねぇ…とダウンロード。
GUI環境からコマンド打ち込みになってしまうの?と思いましたが、GUI環境もとりあえず入っていたり…。

でもこれ日本語にならないな、と思って検索してみると、TortoiseGit – Windowsなら日本語化できるらしい…。

えいっとインストール…した筈がエラーになる。
日本語の言語パッケージしかダウンロードしていなかったようです。本体をインストールしてから日本語化するためのパッケージをインストール。

Git for Windowsはいらなかったんじゃないか…と思いましたがそうではありませんでした。
裏でGit for Windowsが動作していてその補助をしているだけだったからです。

TortoiseGit – Windowsの画面TortoiseGit – Windowsの画面

TortoiseGitの画面。

日本語対応のおかげでGitKrakenではよくわからなかった操作に気がついたり…。
いろいろな操作に幅ひろく対応。

しかし、画面のみやすさや操作のしやすさは…あと一歩…かもしれません。

君には1時間でGitについて知ってもらう(with VSCode) - Qiita
プログラムエディタはBracketsという人だったのですが、Visual Studio CodeでGitHub?

これは使ってみないと…。

VSCodeでGitHubVSCodeでGitHubVSCodeでGitHub

Visual Studio CodeでGitHub。

これはすごい…。
History、差分、その行はいつ変更したものなのかまで…。

エディタで変更したら差分を確認してコミット、プッシュという一連の作業をシームレスに行う事ができるようになりました。

インストールしたGit関連の拡張機能は…。

VSCode 拡張機能

Git History - Visual Studio Marketplace

VSCode 拡張機能

GitLens − Git supercharged - Visual Studio Marketplace

VSCode 拡張機能

GitHub Pull Requests - Visual Studio Marketplace

VSCodeとGitHubの連携もGit for Windowsが裏で仕事をしているので先にインストールしておかないといけないみたいですね。
CUIになってしまうの?と思いながらインストールしましたが大当たり…でした。
posted by さとぴあ at 2019/09/23 17:42 | Web制作

POTI-boardのパスワードハッシュをpassword_hash()に

2018年のパスワードハッシュ - Qiita

ログイン認証と称してmd5とかsha1とか書いてあるソースはゴミなので投げ捨てましょう。
単純なMD5やSHA1ハッシュを元に戻す | Bamboo lath 日々の記録
ハッシュ値は非可逆なので元に戻す事ができない筈なのですが、「aiueo」や「12345」のような単純なパスワードはデーターベースと照合して元に戻す事ができるようです。

POTI-boardは md5() から途中の8文字を抽出してハッシュ化しているので、紹介されている逆引きサイトに8文字のハッシュ値をいれても何もでてきませんが、パスワードが同じならハッシュ値も同じである事に変わりはありません。
PHP: password_hash - Manual

password_hash − パスワードハッシュを作る
password_hash() という簡単に導入できるハッシュ化のための関数があるのに使わない手はない…ですね。

簡単なテストコード。
<?php
$h= password_hash("aiueo", PASSWORD_DEFAULT);
//パスワードは aiueo
echo $h."\n";//ハッシュ値が表示される
$v=password_verify("aiueo",$h);
//ハッシュ値とパスワードを照合
echo $v."\n";//1
var_dump($v);//true
同じパスワードなのにリロードする度にハッシュ値が入れ替わります。

しかし…。
$h= password_hash("aiueo", PASSWORD_DEFAULT);
ではcostが10になってしまいます。
<?php
/**
* このコードは、サーバーをベンチマークして、どの程度のコストに耐えられるかを判断します。
* サーバーに負荷をかけすぎない範囲で、できるだけ高めのコストを設定したいものです。
* 基準として 8 から 10 程度からはじめ、サーバーが十分に高速なら、できるだけ上げていきましょう。
* 以下のコードでは、ストレッチングの時間を 50 ミリ秒以内にすることを狙っています。
* 対話形式のログインを扱う際の許容時間としては、このあたりが妥当なところでしょう。
*/
$timeTarget = 0.05; // 50 ミリ秒

$cost = 8;
do {
$cost++;
$start = microtime(true);
password_hash("test", PASSWORD_BCRYPT, ["cost" => $cost]);
$end = microtime(true);
} while (($end - $start) < $timeTarget);

echo "Appropriate Cost Found: " . $cost . "\n";
?>
さくらのレンタルサーバ ライトでこのテストコードを実行してみたところ最適なcostは9でした。

一番安いライトプランではありますが有料のサーバでもcost10ではサーバに負荷がかかるという事です。
costを10から9に下げると処理時間が半分に。
8にしたらさらに半分…。costが1下がると処理時間が半分になるようです。

ログイン認証を一度だけ行ってログインしたらそのまま…という想定ならcostが10でも耐えられるのかもしれませんが何か一言書き込むだけでパスワードのハッシュ化が行われる掲示板でcost10だとサーバの負荷が高くなってしまうかもしれません。
$pass = $pwd ? password_hash($pwd,PASSWORD_BCRYPT,['cost' => 5]) : "*";
costを5に引き下げました。

cost5では低すぎるのでは?と思ったりもしましたが、コメントを書き込むたびにパスワードをハッシュ化する掲示板なのでこれぐらい下げないと無料のレンタルサーバでは高負荷になる…という判断です。

それでも同じパスワードなら同じハッシュ値という従来のmd5の8文字のハッシュ値とは比べ物にならないぐらい安全性を向上できた…と思うのですが。

この変更は、lot.190823に反映されました。

POTI-board改のダウンロードはこちらから。

お絵かき掲示板はこちら。

file_exists() is_file() 速度比較

ファイルの存在確認をするときに使う関数 file_exists() 、 is_file() の速度を比較するため簡単なコードを書いてテスト。
<?php
$time_start = microtime(true);//計測開始
$img='img/hoge.png';
for($i=0; $i<100000;++$i){//10万回繰り返す
file_exists($img);
}
$time = microtime(true) - $time_start; echo "{$time} 秒";
//計測結果
$time_start = microtime(true);//計測開始
$img='img/hoge.png';
for($i=0; $i<100000;++$i){
is_file($img);
}
$time = microtime(true) - $time_start; echo "{$time} 秒";
//計測結果

//0.37799286842346 秒 0.038822174072266 秒 さくらのレンタルサーバライト
is_file() のほうが、10倍速いという結果がでました。

テストしたコードが単純すぎてキャッシュを確認しているだけだとしても…。
速度差が10倍…なら is_file() で構わないところは is_file() を使ったほうが。

動作の違いは…。
$img='img/';
var_dump(is_file($img));//bool(false)
var_dump(file_exists($img));//bool(true)
$img='img/hoge.png';
var_dump(is_file($img));//bool(true)
var_dump(file_exists($img));//bool(true)
file_exists()は、ディレクトリしかなくても bool(true) を返します。 is_file() では bool(false) になります。

POTI-boardで使用されている file_exists() の該当箇所をしらべてみると…。
ディレクトリの確認をしているかもしれない箇所はほとんどなく逆にディレクトリしかなくても bool(true) では意図した動作にならないところに file_exists() が使用されている事がわかりました。

POTI-boardは一言書いて投稿するだけでもすべてのログを解析してHTMLファイルに書き出します。
そのためログが肥大化すると処理速度が遅くなってしまうのですが…さらに投稿するたびにすべての画像ファイルにアニメファイルがあるかどうか確認しているのでそこに重い関数を使うと…。

投稿時にアニメファイルの存在確認を行う回数が一目でわかるようにdumpしてみました。

file_exists()をis_file()に

アニメファイルの存在確認を file_exists() から is_file() に書き換えたところ8秒かかっていた投稿処理時間が1秒に短縮。

運営している絵板は設置件数が多くログ保持件数が多いのに一番安いさくらのレンタルサーバ ライトのライトプランなので、遅くても仕方がないのかな?と思っていたのですがどうにか…。

この変更は、POTI-board改 v1.52.9 lot.190812に反映されました。
(最新版は v1.53.2 lot.190831)

POTI-board改のダウンロードはこちらから。

お絵かき掲示板はこちら。

phpのOpenSSL関数で暗号化 復号化

phpでpasswordを暗号化して復号化…。
password_hash()は暗号化ではなくハッシュ化なので元のpasswordに戻す事はできません。
ではどうしたら…。
PHPで文字列を暗号化 - Qiita
なんか複雑なコードが書いてある…。これは私には手におえない?
phpのマニュアルは…。

PHP: OpenSSL 関数 - Manual

PHP マニュアル 関数リファレンス 暗号 OpenSSL
目次が…。
という事でできてみればたったこれだけ…のコードに1時間以上…。
<?php
$pwd = 'hogefuga';
define('crypt_pass','VNCLiX9BaeuzfaR');//暗号鍵
define('crypt_method','aes-128-cbc');//method
define('crypt_iv','FpXe2VNEVwLhJa8a');//iv 16バイト
$pwd=openssl_encrypt ($pwd,crypt_method, crypt_pass, true, crypt_iv);//暗号化
$pwd=bin2hex($pwd);//16進数に
var_dump($pwd);
//string(32) "9427c68b3e6ba3468c773d1b8f54359a"
$pwd=hex2bin($pwd);//バイナリに
$pwd=openssl_decrypt($pwd,crypt_method, crypt_pass, true, crypt_iv);
var_dump($pwd);// string(8) "hogefuga"
ivは半角16文字(16バイト)で。
暗号鍵は暗号化復号化のための固有の文字列。
methodは aes-128-cbc。

暗号化したpasswordをバイナリから16進数に変換したものをGETで取得して、16進数をバイナリに戻して復号化。

続きから描く時にペイント画面に入るpasswordを暗号化する事ができました。

この変更は、POTI-board改 v1.53.0 lot.190823 に反映されました。

お絵かき掲示板はこちら。

$_POST $_GET から filter_input()へ

POTI-boardの$delに不正な値が入らないようにする: STP^3
でこう書きました。
$del = ( isset($_POST["del"]) === true ) ? ($_POST["del"]): "";

if(is_array($del)){
$countdel=count($del);
for($i = 0; $i < $countdel; $i++){
if(!ctype_digit($del[$i])){//数字のみ
$del="";
}
}
}
else{
$del="";
}
数字しか入らなくする工夫だったのですが…。
foreachを使ったほうが的確だったかも。そして…。
$_GET, $_POST じゃなくて filter_input 使えとのこと - Qiita
$del = filter_input(INPUT_POST,'del',FILTER_VALIDATE_INT,FILTER_REQUIRE_ARRAY);//$del は配列
配列にもfilter_input() を使う事ができるので FILTER_VALIDATE_INT で整数以外入らなくなりました。とてもスマートです。

$_POST $_GET から filter_input()へ
$anime = filter_input(INPUT_POST, 'anime',FILTER_VALIDATE_BOOLEAN);
bool型以外受け付けないので、入る値はtrueまたはfalseのみ。
取得する値がないときは変数にNULLがセットされるので未定義になりません。
【PHP入門講座】 NULLと未定義の違い - Qiita
$_POST[]は書き換える事ができるので意図しない値が入る可能性…。スクリプトの先頭で取得するだけなら問題ないのかもしれませんが途中で他の値を代入しているスクリプトも存在していて…httpからPOSTされたデータなのか、代入して書き換えられた値なのかわからなくなるケースもあるようです。
PHP - スーパーグローバル変数に直接アクセスしない方がいい理由|teratail

filter_input()を使った場合、スーパーグローバルの$_GETや$_POSTではなく、本当にHTTPで投げられた値を元に結果を返します。
この変更はPOTI-board改 v1.51.9 lot.190612に反映されました。
注意:2019年8月29日現在の最新版は POTI-board改 v1.53.1 lot.190827です。

POTI-board改の最新版のダウンロードはこちらから。
お絵かき掲示板はこちら。

Painter2020 ブラシ消しゴム切り替え遅延 Paintstormというアプリもある

いろいろと問題があってもPainterの開発が終わってしまったら困るのでアップグレードしようと思っていました。
しかし…。問題が多すぎました。

Painter2020

ブラシから消しゴムへの切り替えが遅延するので、線を描いて消しゴムで消す作業をショートカットキーで行う時に消しゴムになっていてほしいのに鉛筆のまま…。

UIの更新も最初はいいな…と思ったのですが…。

Painter2020

用紙を選択するとこの画面が消えてしまうので、用紙を選択して拡大率を変更する時は開き直す事になります。
結局従来どおり用紙パネルを開いたまま作業…。

Painter2020

システムは推奨仕様を満足しています。
満たしていますの誤訳だと思いますが製品の出荷前にチェックする事はできなかったのでしょうか?

ブラシ→消しゴムの切り替え遅延はGPUがオンボードだからから?と思いましたがこのベンチマークテストの結果を見る限りGPUの問題ではなさそうです。

CPUは第8世代のCore i5です。

たしかにやたら安かったAcerのパソコンですがまだ買ったばかり…。

Acer デスクトップパソコン Aspire Core i5-8400/8GB

いまとなっては、思っていたほど速くないような気もするのですが…。
6年前のCeleronからの買い替えです…。それにくらべると爆速PCになった筈なんですけどね。

Painter2020があまり良くないとなると、次のバージョンで改善されるかどうかもわからないのでクリスタとMediBang Paintになれるしかないのかな…と思いましたが…。

Paintstorm Studio

Paintstorm Studio | Professional software for digital painting



Paintstorm Studio。

Painterのブラシの完全な再現はできないものの、似たような塗り方をする事ができました。

混色系のブラシがきちんと動作しているのでラフに塗って混色してならすPainterと近い感覚で作業する事ができます。

おまけに19ドルで日本円にして2千円ちょっとです。

それにしては知名度が低い…。
UIの日本語対応が比較的最近だった事もあるのかもしれません。

カスタムパレットもありますし、ブラシの設定項目もPainterの設定項目を知っている方なら設定項目が多すぎて…とならないと思います。
必要な設定項目だけカスタムパレットに保存しておく事もできます。

キーボード・ショートカットの設定は項目のダブルクリックとスライダーの上で右クリックなど。

英語のマニュアルに反応しない時はダブルクリックの間隔を短くしてみてくださいとありました。
すばやくダブルクリックしたところ設定する事ができました。
posted by さとぴあ at 2019/08/05 15:56 | Painter

お絵かき掲示板交流サイトのトップページの負荷削減

お絵かき掲示板交流サイトのトップページの新着画像の表示に使っていたスクリプト…。
foreach(glob('cgi/{foo,bar,baz}/src/{*.png,*.jpg}', GLOB_BRACE) as $filename) {
//$arr[$filename] = filemtime($filename);
$arr[$filename] = substr($filename,-17,-4);
}
unset($filename);
//連想配列を値でソート
arsort($arr);
?>
お絵かき掲示板の画像が保存されているディレクトリに入っている画像をすべて呼び出して新着画像順になるようにソート。

以前はファイルのタイムスタンプで並び替えていましたがもしひとつのディレクトリに2000枚の画像があったらディレクトリ3つで合計6000枚。

それを配列にいれるだけでなくサーバにタイムスタンプを問い合わせる処理もはいって…となるのでその処理が負荷になっていました。

それをファイル名でソートするようにすると0.09秒かかっていた処理が0.03秒に短縮。
//$arr[$filename] = filemtime($filename);
$arr[$filename] = substr($filename,-17,-4);
POTI-boardの画像ファイルのファイル名には10桁のユニックスタイムと小数点以下のマイクロタイム3桁分、合計13桁の数字が入っているのでその箇所とりだしてファイル名でソートしても同じ結果を得ることができました。

しかし、表示する画像が新着の1枚でも12枚でもglobでディレクトリ内の画像を検索して6000枚画像があったら配列の数も6000…。

あれ?ログファイルから画像のファイルのパスを取得したら?とひらめいて…。
$i=1;
$fp = fopen($val, "r");
while ($line = fgets($fp ,4096)) {
list($no,,$name,,$sub,,,
,,$ext,,,$time,,,,) = explode(",", $line);
if ($ext){
$dir=explode('/',$val);
$files[]=$no.','.$name.','.$sub.','.$dir[1].',cgi/'.$dir[1].'/src/'.$time.$ext;
// var_dump($val);
if($i>=12){break;}
++$i;
}
}
fclose($fp);
各ディレクトリの新着12枚をもとにして全ディレクトリ分の配列を作成してファイル名でソートすれば…。

12x3=36で配列の数36。

結果処理時間を0.09秒から0.006秒に短縮することができました。

従来の1/15の処理時間でほぼ同じ結果を得ることができました。
いろいろとやってみるものですね。

お絵かき掲示板交流サイトはこちら。

わかると便利なforeach

あんまりにもあんまりなコードを書いていたので、少しは進歩している事をおしらせすべく、お絵かき掲示板交流サイトのトップページで使っているphpのソースの一部を…。

<?php
$arr = array();
foreach(glob('cgi/{foo,bar,baz}/index.html', GLOB_BRACE) as $filename) {
$arr[$filename] = $filename;
}
$i = 1;
foreach($arr as $key => $value){
var_dump($key);
if($i >= 3){break;}
$i++;
}
?>

よくわからないけれど動いていたもの。

foreachは配列の数だけループするのでもし3ならbreakという処理は必要ありませんでした。

globで配列に入れる必要もありませんでした。その配列を別の配列に入れる必要もありませんでした。

<?php
$arr=array('cgi/foo/index.html','cgi/bar/index.html','cgi/baz/index.html');
for($i = 0; $i <= 2; $i++){
$filename = $arr[$i];
var_dump($filename);
}
?>

foreachがよくわからなかったので、forで記述。
しかしやや煩雑なコード…。

<?php
$arr=array('cgi/foo/index.html','cgi/bar/index.html','cgi/baz/index.html');
foreach($arr as $filename){
var_dump($filename);
}
?>

foreachが便利な事がわかったので書き直し。
配列の数だけループ。

お絵かき掲示板はこちら。