それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

任意の拡張子(.jpg/.zip/.ico) をApacheHandlerでcgi/php処理する

ブラウザでURL画像をクリックしたら、php起動したい

画像のURLをクリックすると、WEBサーバから画像が送信される。当たり前のことですが、この当たり前の処理に、ハンドラを加えてプログラムを追加したいと思います。

http://example.com/img/top_banner.jpg

通常処理の場合

WEBサーバーは次の処理をする。

  1. URLにリクエスト来る
  2. URL からOSパスに変換する。
  3. 該当パスのファイルを実行して返す

Apacheのモジュールや設定はそれぞれ段階で処理を挟みますよね。

  • mod_rewrite は リクエストを書換
  • < Location> はOSパス変換をスキップ
  • .htaccess チェックは OS パス変換
  • Allows は該当ファイルの実行時に
  • 実行はhandler に任せる。またはファイル中身を送信

今回はハンドラを追加して、バイナリを処理する

画像を自動変換する、画像の直リンク(リファラ・セッション)をチェックなど。

これらを使ってApacheのハンドラを見なおしてみる。

画像URLをPHPで処理する基本的な考え方

次の流れで、JPGファイルを送信するのではなく、間にハンドラを挟むところ。

ポイントは jpg にハンドラ(関連付け)を行う。その実行する関連付けるプログラムを自分で書こうってはなし。

Apacheのハンドラは拡張子毎に登録します。ApacheがOSと変わらん動作をするのでチャント使うと便利ってことです。

最初にハンドラを用意します。

Apache の設定側に ScriptAliasを設定。設定ディレクトリにCGI実行を許可する。

  ScriptAlias "/cgi-bin/" "/var/www/example.com/cgi-bin/"
  <Directory /var/www/example.com/cgi-bin/>
    # AllowOverride None
    Addhandler application/x-httpd-php .php
    Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
    Order allow,deny
    Allow from all
  </Directory>

許可したディレクトリに、独自のハンドラを追加。Apacheリロード。

$ cd /var/www/example.com/cgi-bin/
$ echo "<?php phpinfo();" > info.php

念のため、単体でphpが実行できることを確認

curl -v http://example.com/cgi-bin/info.php | grep _SERVER["SCRIPT_FILENAME"]
/var/www/example.com/cgi-bin/info.php

これで準備終わり。はい簡単です。

拡張子JPGを、作成した info.php で処理移譲するハンドラ設定をします。

Action my_sample /cgi-bin/info.php
AddHandler my_sample .jpg

Actionで my_sample という名前で/cgi-bin/info.php を登録する 拡張子JPGを処理するのを my_sample ハンドラに設定する。

この設定を好きな場所(htaccess / directory / conf ) に記述すればオッケ。

今回は.htaccessで /var/www/example.com/img/.htaccess に書いた。

完成したら、jpg にアクセスしてみる

curl -v http://example.com/img/sample.jpg | grep _SERVER["SCRIPT_FILENAME"]

出来た。これで指定の拡張子を任意のプログラムでApache実行できることがわかるね。

リクエストが来たファイル名はPATH_INFOでわかるね。

自分でプログラムを書いてそれで処理できる。それがCGI

CGIの仕組みは、自分でプログラムを書いて、そのプログラムを指定拡張子に関連付け、またはディレクトリを関連付けが本来の姿だった。

そのプログラムをphp / ruby / clang で記述すればいいわけですよね。

画像処理するCGIの例

画像やバイナリを関連付けで、処理するのにはいくつか便利な方法がある

  • 画像のリサイズ
  • 画像のリファラチェック
  • 画像の直リンク時にHTMLを表示する

一番大きいのは GET引数が使えること

http://example.com/img/sample.jpg?width=100

次に大きいのはリクエスト引数の文字列を使わなくてイイ

Apache側でファイルの存在確認と実行確認、パーミッションチェックまでヤってくれる。

http://example.com/show_img.php?path=sample.jpg&width=100

このような、ファイルの処理にまつわる処理を安全にできる。

パス変換やファイル存在チェックまではapahce側に依存できる。自分でプログラム書いたりフレームワークに頼らなくていい。ディレクトリ・トラバーサル脆弱性などに対応できうる。

php'er フレームワーク使いすぎ問題。CGIでいい。

ファイル処理くらい1枚のCGIで終わるものを、フレームワークかいてテストって意味なくね?

アップロード・ファイル処理する系はCGIが強いです。

js/cssPHP処理するときはコレ

拡張子 CSSもJavaScriptもPHPで処理しちゃう話 - それマグで!

js / cssPHPで処理しちゃうと楽しいよ。

ob_gzhandler が 画像に効かないので強引にやる

ob_gzhandler が画像を無視する

gz が付いたphpから、content-type: image/jpeg を設定すると transfer-encoding : chunked になってしまい、GZipで転送されない・

<?php

ob_start("ob_gzhandler");
header("content-type: image/jpeg");//この時点でgz_handler は無視される
imagejpeg( $gd_image,);
ob_end_flush();

テキストなら、圧縮されるが、画像は警告無しで無条件で無視された。なるほど。

gzipでコンテンツの圧縮をするとかなり削減できる

text 系は本当に小さくなる。画像にはあまり効果がない。画像はHTTP的にGzipを掛けるべきではない。

原則として画像を小さくするには、画質を落とす、幅を小さくするなどして圧縮すべきである。とのこと。

google 曰く

画像をgzip 圧縮するより、画質を落とすことを考えろ

とのことでした。わかるんだけど・・・・・・・・・・・・・・・・・・・・

違うんだ、私は 画像をgzip圧縮したいんだ!

オリジナル画像を少しでも圧縮して転送したい。

画質を劣化させることは本意ではない。gzip を最高圧縮9でやればJPEGでも10〜20%程度は容量を削減できるし。強引にヤってみた。

JPEGを強引に圧縮

<?php
      header("content-type: image/jpeg; ");

      ob_start();
      imagejpeg($img);
      $data = ob_get_contents();
      ob_end_clean();

      $gz_data = gzencode( $data , 9);

      header('Content-Encoding: gzip');
      header("content-type: image/jpeg; ");
      header("Content-Length: ". strlen($gz_data) );
      ob_start();
      echo ($gz_data);
      ob_end_flush();

      imagedestroy($img);
      return ;
?>

これで、ほんの少しだけ節約できるはず。

適用前

Content-Encoding: gzip
Content-Length: 855241
Content-Type: image/jpeg;

適用後

Content-Encoding: gzip
Content-Length: 749838
Content-Type: image/jpeg;

多少は、小さくなりました。でもやっぱり、幅を50%とかにしたほうが節約量圧倒的なので、できれば幅を変えたほうが良いよね。

webP も考えたのだけれど、iOS Safari非対応だし、アプリ側でlibwebp 組み込めばできるけど・・・

コンテンツをgzip 圧縮する gz hander とても楽だった

コンテンツを圧縮するには、1つ書くだけ

<?php
ob_start("ob_gzhander");

たったこれだけ。たったこれだけ。楽チンですね―

え?if 文は accept-encoding は?

ブラウザが非対応ならどうするの?、IFぶんで条件分岐は?それが、いらないんです。私も実験して驚きました。

実験してみました。

<?php

ob_start('ob_gzhander');
phpinfo();
header("Content-Length: ".ob_get_length());
ob_end_flush();

単純に、ob_start を追記しただけです。

gzip 非対応(Accept-Encoding 無し )の場合

非対応なら、生のHTMLを返す(バッファリングは失敗するので、処理されない)

curl  -v  https://localhost/info.php   > /dev/null
< HTTP/1.1 200 OK
< Date: Sat, 14 May 2016 10:46:45 GMT
< Server: Apache/2.2.22 (Debian) Phusion_Passenger/5.0.23 PHP/5.4.45-0+deb7u2 mod_ssl/2.2.22 OpenSSL/1.0.1e
< X-Powered-By: PHP/5.4.45-0+deb7u2
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
< Content-Type: text/html

gzip 対応(Accept-Encoding 有り)の場合

対応なら、HTMLのバッファリングが成功するので、圧縮されたコンテンツが飛んでくる

curl  -v  https://localhost/info.php   -H 'Accept-Encoding: gzip, deflate, sdch' > /dev/null 
< HTTP/1.1 200 OK
< Date: Sat, 14 May 2016 10:53:58 GMT
< Server: Apache/2.2.22 (Debian) Phusion_Passenger/5.0.23 PHP/5.4.45-0+deb7u2 mod_ssl/2.2.22 OpenSSL/1.0.1e
< X-Powered-By: PHP/5.4.45-0+deb7u2
< Vary: Accept-Encoding
< Content-Encoding: gzip
< Content-Length: 11219
< Content-Type: text/html
<

ちゃんと圧縮されて飛んできます。

調べたら安心。

チャント調べたら安心できますね。

追記

自動適用されるのは content-type : text/**だけでした。 image は自分でやる必要がありますね。

github への接続パスワードを省略する(HTTPS編)

githubHTTPSで使うことが多くなった。

https のURLを最近使うことが多い。ssh のほうが正直言って使いやすいんだけど。

ついついhttps のでコピペしちゃうので、HTTPS向けの設定をすることにした

credential.helper store

パスワードを、ファイルに保存する設定。

git config --global credential.helper store 

storeを設定した後に git clone/pushをすれば、ファイルに保存される。

パスワードファイルに注意

通常パスワードはプレーンテキストでファイルに保存されるので、取扱には注意が必要。

global の保存先は $HOMEなので

~/.git-credentials

ここに保存される。繰返しになるけど、文字列そのまま入ってるので注意。

ちなみにOSXは デフォルトでKeychainに保存するので設定不要

どうしてOSXは設定不要で動いていたのか考えていたら、設定の保存先が keychains だった。コレは便利すぎる。

credential.helper=osxkeychain

OSXだと安心して使えますね。

参考資料

http://stackoverflow.com/questions/11403407/git-asks-for-username-everytime-i-push

https://git-scm.com/docs/git-credential-store

php のシェル呼出しで引数を後から決める、変数内の文字列展開をする方法

php でコマンドを実行するとき、コマンド組み立てが、美しくない

$src = "my-sample.jpg"
$dst = "out.png"
$command = "convert $src $dst" ;

文字列の展開タイミングがあるので、これをクラスにすると面倒くさいんだよね。

コマンドを扱うクラスを作ると処理が面倒

文字列展開を後でやろうとすると出来無い。

<?php

class MySample{

  public $command = 'convert  $src $dst'; //あとで文字列展開をしたい
  public function __construct(){ /*なにかしょり*/}
  public function convert (){
    $src = escapeshellarg($this->source_file_name());
    $dst = escapeshellarg($this->destination_file_name()));
    $command = "{$this->command}" // "convert $src $dst" ; を展開したいけど出来ない。。。
  }
}

こうなると、文字列展開を後でするには、コマンドをメソッド中で組み立てる必要があり、これがコマンド文字列をデバッグするのが面倒になる原因。

解決策1: putenv を使う (シェル呼び出し時はオススメ)

putenv で環境変数に直接php変数を渡してあげる。シェル呼び出し時に環境変数を利用することで、見通しがすっきるする

<?php

class MySample{

  public $command = 'convert  $src $dst'; //あとで文字列展開をしたい
  public function __construct(){ /*なにかしょり*/}
  public function convert (){
    $src = escapeshellarg($this->source_file_name());
    $dst = escapeshellarg($this->destination_file_name()));

    putenv("src=$src");
    putenv("dst=$dst");

    ## シェル実行時に環境変数が使われる
    shell_exec($this->command);

    putenv("src=''");
    putenv("dst=''");

  }
}

putenv で環境変数を渡すのが結構便利だった。

コマンドに記述ミスが有ると思ったら、$this->command の中身をそのまま取り出せば、コピペで簡単に再現でき、シェルで実行がとても楽になる。

動作チェック、再実行したい時も簡単に、シェル起動してコピペで済む。

$ > src=my_jpg dst=out.jpg  convert  $src $dst

シェル呼び出しに使うコマンドを動的に組み立てないので、シェルスクリプトで使ってるコマンドをそのまま使うことが出来る。

追記:環境変数で突っ込む前に escapeshellargs されたら上手く動作しないよ。変数に無事突っ込めた時点でエスケープ不要だろうしね。。

解決策2: sprintf を使う

関数sprintfを使えば少しだけ、すっきりする。

<?php

class MySample{

  public $command = 'convert  %s %s'; //あとで文字列展開をしたい
  public function __construct(){ /*なにかしょり*/}
  public function convert (){
    $src = escapeshellarg($this->source_file_name());
    $dst = escapeshellarg($this->destination_file_name()));
    $command = vsprintf( $this->command, [$src, $dst] );// sprinft で文字を埋め込み
  }
}

文字列として展開される引数を後から決られるので、すっきりする。でも %s がたくさんあってワケガワカラナイヨ。

あとコマンド文字列が何を意味しているのか。%sでは変数の意図がでもわかりづらくなる。

解決策3:evalする

eval すれば出来る。

<?php
class MySample{

  public $command = 'convert  $src $dst'; //あとで文字列展開をしたい
  public function __construct(){ /*なにかしょり*/}
  public function convert () {
    $src = escapeshellarg($this->src);
    $dst = escapeshellarg($this->dst);
    eval("\$command =\"{$this->command}\";");
    }
  }

eval を活用すれば、出来ることがわかる。でもエスケープが多い。eval の代わりに php://memory に書き出して include なども使えそう。

eval を変数展開に使うのは個人的には使いたくない。もしやるとしたら

<?php
function expand_string( $string, $assoc_array ){
  extract($assoc_array);
  eval("\$ret = \"$string\";");
  return $ret;
}

などと先に関数を定義しとかないとevalで何したいのか、一目でわかりづらくて困る。

解決策4:関数を作る

これもeval とあんまり変わらないんだけど、関数をつくて、コールすれば用を満たせる。

<?php
$command = 'convert $src $dst';
$f = create_function('$src,$dst',  "return \"{$command}\" ;" );
shell_exec(  $f( "src.jpg", "dst.jpg"  )) ;

関数を作るとあとで中身が評価されるため、使い回し出来そう

環境変数を渡すのが便利だった。

シェルで作ったコマンドを、.bash_history から持ってきて貼り付けるだけだったので楽でした。

文字列を展開する方法は他にもあるかな?

  • シェルに任せる
  • eval
  • 関数作成
  • sprintf する
  • include する

他にいい方法ないのかなぁ。

phpで複数行のシェル呼び出しをバックグラウンドにする

php でシェル呼び出しをバックグラウンドにするには

シェル経由のコマンド実行をバックグラウンド(プロセスの親 にする)には次のとおりに書く。

<?php
shell_exec ( "sleep 100 > /dev/null 2>/dev/null & ");

STDOUT/STDERRをphp から切り離せば、プロセスをバックグラウンド・ジョブにすることが出来る。

複数行ならどうするのか

コマンド1行に対して1つの & が必要なので、複数行呼び出すときは複数回 & をすると大変なことになる。

これはひどい結果になる。

この場合、次々とコマンドを呼び出だすだけになる。

<?php
shell_exec ( "sleep 100 > /dev/null 2>/dev/null & ");
shell_exec ( "sleep 100 > /dev/null 2>/dev/null & ");
shell_exec ( "sleep 100 > /dev/null 2>/dev/null & ");
shell_exec ( "sleep 100 > /dev/null 2>/dev/null & ");

このコマンドが、一時ファイルを作って作業して一時ファイルを消すような処理をしていると、処理中の一時ファイルが先に消されちゃったりする。

複数行に渡るコマンドを実行するには

コマンドを { $cmd } のように 括弧で区切る方法が一番楽

<?php
shell_exec ( "{sleep 100;sleep 100;sleep 100;sleep 100;} > /dev/null 2>/dev/null & ");

これは、気づくのに時間がかかった。シェル呼び出しは 括弧{} でくくってあげると一括りのコマンドとして実行できるんですね

shell_exec で 2&1>/dev/null & をつけると、が sh -c 経由になるので もしやと思ったらビンゴだった。

カッコつきのコマンドのエラーを探すには

括弧をつけると、シェルスクリプトのエラーを探すのが面倒になる。エラーが出た時に追いかけるのが面倒です。

この場合は、エラーと標準出力の書き出し先を明示してあげれば楽ちんになった。

<?php
shell_exec ( "sleep 100 > /tmp/stdout 2>/tmp/stderr & ");

phpの shell_exec 関数は 標準出入力がファイルに流されてて、&がついてたら apache プロセスから切り離すようになるみたいです。

関連資料

takuya-1st.hatenablog.jp

2018-03-04

バックグラウンドでroot は書きすぎなので削るなど

pdftk で null pointer exceptionでたのでビルドした

pdftk を使ってて ヌルポ出た

pdftk で null pointer が出るなんて、一瞬驚きました。 まさかJavaで出来てたなんて。

pdftk で null pointer が出た条件

  • pftk 1.4.4
  • gcj

この条件下でエラーになるようです。

対処法

公式のバグレポートにバグレポでてました。 pdftk 2.0.1 で fix されているようです。

公式から最新版を落としてきて make します。

pdftk のビルド

wget https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/pdftk-2.02-src.zip
cd pdftk-2.02-dist/
cd pdftk
cp Makefile.Debian Makefile
make

もし、gcjが指定と違う場合や、gcj がない場合。

sudo apt install gcj-jdk
vim Makefile # gcj のバージョンを書換

これでnulllpointer が出なくなります。

http ヘッダでブラウザをリロードする retry-after と refreshヘッダ

時間のかかる処理のHTTPリクエストへの対応

HTTPリクエストで、時間のかかる処理を受け取った時どうするか。

すぐに思いつくのは websocket や ajax で pollingしたりpush 通知する方法でしょうが、面倒くさいんだよね。

http ヘッダを見なおしてみる

ブラウザにリロードを命令する方法が無いのか、ヘッダを見なおしてみた。

  • retry-after ヘッダ
  • refresh ヘッダ

この2つのヘッダが定義されていることがわかる。

retry-after はブラウザ実装が微妙

retry-after はまさにバッチ処理の為に作られたようなHTTPヘッダなのだが、これを見てるのはGoogleBotくらいらしい。

もし使うとしたら、 202 Accepted503 Service unavailable などとともに使うことになるだろうがブラウザ側が実装してないので、使えない

実際にChrome/Safariで実験してみたが、全く相手にされなかった。ツライ

Refresh ヘッダ

昔々の太古の時代からあるヘッダで、これは HTMLに記述して使われることが多かった。

<meta http-equiv="refresh:5 ; url=/page.html" />
<body>
ページをリダイレクトします
</body>

リダイレクトするページを入れるときは404ページのテンプレなどでよく使われた手段ですよね。邪魔だったから最近あまりみない。

http-equiv はヘッダ同等の意味なので

http-equiv で refresh が動くとは、すなわちHEADERに埋め込んで利用可能である。

<?php
header("refresh : 3 ; url= / ");

phpで例を記述しましたが、HTTPヘッダなので基本的にどこでも動作する。

URLには、相対パス絶対パス・完全URLが使える。リダイレクトで使えるものならなんでも出来そう。

時間のかかるバッチ処理へのリクエストに有効

バッチ処理をうけて、処理結果を待つときに、Refreshが使えそう。

Javascriptで良いじゃん?と思うんだろうけど、動画・画像・音楽など、HTML中にコンテンツを埋め込むときに処理待ちをさせるのに便利。

ローディングアイコンでクルクルさせるのもいいんだけど、画像などで使ったら、ブラウザを待たせるのに、とっても楽チンだと思うんだよね。

でも、画像に使えない。

ここまで書いていて何なんだけど、ブラウザは img 要素への refresh を全く無視してしまう。

惜しい、実に惜しい。画像生成を待たせるのに良いと思ったんだけどねー

onerror を使うしか無い

画像のonerror を使うしか無いね。サーバー側で 404などエラーを返すと onerror が発動するのでそこでリロードするしか無い。面倒くさい。

<img src="" onerror="function(){}" />

pdf のページ数をコマンドで確認する

pdftk でページ数の確認ができる

pdftk target.pdf dump_data

pdftk でほとんどの問題は解決するんだけど。pdftk が gcj で null pointer 吐くことがあるので油断できない。

まぁコマンドじゃなく pdf のバイナリを読めって話なんだけど面倒だよね。

2017-01-23 追記

ページ数だけだと、pdftk は遅いのでpdfinfo の方が早い。

takuya-1st.hatenablog.jp

比較

time pdftk  out.pdf  dump_data
real    0m24.755s
user    0m9.767s
sys 0m13.269s
time pdfinfo out.pdf
real    0m0.086s
user    0m0.072s
sys     0m0.012s

ページ数だけなら圧倒的にpdfinfo の勝ち

その他

imagemagick convert コマンドでも処理できるが、convert だと 5分かかったので、話にならない

tar 展開 gzip / xz / bz2

tar で 圧縮ファイルを伸張するときのオプション早見用

tar zxf sample.tar.gz
tar Jxf sample.tar.xz
tar jxf sample.tar.bz2

よく忘れるんだよね。

tar コマンドで gz がメジャーだったけど最近は xz や bz2 が増えてきたもんね。解凍するときにコマンドオプションを忘れそうになる。

j/ J / z が bxz って覚えておくと展開するときに楽そう

MySQL でCurrent TimeStampを複数カラムで使う小手先テクニック

current_timesptam 便利だけど。

複数カラムには設定できない。

 create table my_test
 (
  id int primary key  auto_increment, 
  path  text  not null default "" , locked tinyint not null default 0 , 
  created_at timestamp not null default current_timestamp,
  modified_at timestamp not null  default current_timestamp 
)
;
ERROR 1293 (HY000): Incorrect table definition;
there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause

current_timestamp を複数カラムに設定するには

非常に面倒くさいテクニックがアリまして。

timestamp not null  のカラムに null を入れる。

not null に null を入れると current_timestap が導入される。なんともユーザーの期待を裏切る仕様

これでこうなる。

+----+----------------------------+--------+---------------------+---------------------+
| id | path                       | locked | created_at          | modified_at         |
+----+----------------------------+--------+---------------------+---------------------+
| 17 | /home/takuya/test.1.jpeg   |      1 | 2016-05-09 04:53:16 | 2016-05-09 04:53:54 |
| 18 | /home/takuya/test.1.jpg    |      0 | 2016-05-09 04:53:34 | 2016-05-09 04:53:34 |
+----+----------------------------+--------+---------------------+---------------------+

current_timestamp を複数カラムに設定するときの小手先

create table で not null 入れる

  created_at timestamp not null ,
  modified_at timestamp not null  on update current timestamp_default current_timestamp

null を指定する

insert into mytable ( path, created_at) values ( "/path/to/name", null );

not null テーブル・カラムに null 入れるなんて、コードレビューでRejectしてたんだが、まさかこんなことになってたとは

自前Chrome拡張機能がオフにされるのを防ぐ。強制オフされるのを避ける。

chrome 34 あたりから警告出るようになりました。

chrome 33-35 の周辺で警告が出続けます。

CRX 、 拡張子UserJSもダメです。

以前は、拡張子 sample.user.js を放り込んでいけばユーザーJSが使えて便利でしたが。ソレもできなくなりました。

自分で作った野良拡張機能Chromeに放り込めなくなっています。

強制的に disabled にされます。

開発者モードでもダメです。

警告が出続けます。

f:id:takuya_1st:20160508225258j:plain

警告くらいべつにどってことないけど、起動時に毎回出るのはツライ。

対処法

  • chrome のチャンネルを変える。
    • beta チャンネルを使う(← 使えない。2016-05-08確認
    • dev チャンネルを使う(← JS の互換性エラーでバグるサイトが多すぎ ex ドコモ)
  • その他のブラウザを使う
    • vivalid (←オススメ
    • Chromium
    • Comodo Dragon
  • 起動オプションをつける。
  • WebStoreにアップする。(←オススメ

dev/beta を場合

chrome beta を使えたら出来たが、出来なくなった。

dev は常用するにはちょっとシンドい。Devが原因かサイトが原因か、拡張機能が原因か切り分けが面倒。というか、動いてないことに気づかずブラウジングしててはまることがある。

他のブラウザを使う。

UserJS の ドラッグドロップが動くので vivaldi は良いんじゃないかと思う。「友人たちのためのブラウザ」を名乗るので、便利機能を消すような真似はしないだろうし。

その他、色々あるのでぐぐったら見つかると思う。

起動オプションを使う。

Windowsだとコレが確実かも。Mac OSXだと起動オプションをつけるのが面倒なのですが

起動オプション

 --enable-easy-off-store-extension-install

OSX の場合

open -a "Google Chrome.app" --args  --enable-easy-off-store-extension-install

OSX の場合は、automatorでAPPにしないとSpotlightから起動が面倒になります。

WebStore に開発者アカウント作る

今なら500円位だった。将来的にはどうなるかわからないけど。

公開ベレルが設定できるので、ソレで動く。

  • WebStore に表示する。
  • WebStoreに陳列せず、URL知ってる人だけインストール可能
  • WebStoreにもURLも使わせない(インストール不可・アップだけ)

2番めの方法だとある程度プライベートな物が作れる。

またExtensionをWebStoreにアップするとプロファイルに保存されるんので、自動更新やChromeログインで拡張機能が自動ロードされるのが強い

ただし、これらはGoogleの審査がくるので、ある日突然停止されることもあるだろうし。公開数上限もありそうだし。怖い。

OSX Safari拡張機能AppleのDeveloper 登録が必要で年額100$は高い。

その点、5米ドル程度でしばらく使えるGoogle Webstore開発者アカウントは便利かもしれない。

その他 tampermonkey を使う。

ちょっとしたUserJS程度なら、拡張機能をインストールしなくても GreaseMonkey を使う tampermonkey を使うのも良いかもしれない。

個人的にはGreaseMonkeyで解決せずに拡張機能のノウハウを集めたいんだよなぁ。

オマケ。

強制的にdisabeされた、UserJSの拡張機能をオンにするには、Chrome Apps & Extensions Developer Toolで 強制ONにするボタンがクリックできますが、直ぐにオフにされます。

いつまで出来るのか。

拡張機能は無くなって行くのかも。拡張機能Googleは消したい方向っぽいよね。セキュリティ対策という正義で言われちゃどうしようもないし。IEのシェア抜いちゃった今では、1番保守的になる可能性が高いよね。

参考資料

https://productforums.google.com/forum/#!topic/chrome-ja/7qSACiy8EtY

Chromeで無効化されたcrxファイルを動かす - ねとめもー

https://vivaldi.com/?lang=ja

http://superuser.com/questions/767286/re-enable-extensions-not-coming-from-chrome-web-store-on-chrome-v35-with-enhan

php rmdir() で空じゃないフォルダを消すには?

php の rmdir には forece オプションがない。

普通に rmdir すると not empty directory って怒られるんですよね。

みんなどうやってんのかなーって調べたら system("rm -rf $target") してるみたい

せっかくなのでSPLで書いてみました。

<?php

function rm_f( $path ){

  $dir = new DirectoryIterator($path);
  if ( !$dir->isDir() ) { return false; }
  foreach($dir as $e ){
    if ( $e->isDot() ) continue;

    if ( $e->isDir() ) {
      rm_f($e->getPathName());
      rmdir($e->getPathName());
    }else{
      unlink ( $e->getPathName() ) ;
    }
  }
  return rmdir($path);

}

rm_f("/tmp/php-pdf-extractaUNYfA");

SPLが5.3あたりから標準仕様になっていて嬉しい。SPLはちょっと痒いところに手が届きそうで届かないもどかしい感じがすき。

ついでなのでglob で書いてみました

<?php

function rm_rf($path){
foreach( glob("$path/*") as $e ){
  if(is_directory($e)){ rm_rf($e);}
  else{unlink($e);}
}
rmdir($path);
}

ほかにも

  • FilesystemIterator
  • glob
  • opendir
  • readdir
  • array_walk_recursive

などなど再帰と配列が使えるものならなんでも出来そう。

ZIPとrm-rf の苦い記憶

通常はシェルでいいと思います。

<?php
shell_exec( "rm -rf $tmpname");

べつにシェルでもシェルでも。

<?php
$rm_command = "rm -rf \$TARGET"; //先にコマンド作っておいて
//exec
putenv("TARGET=". escapeshellarg($path));
shell_exec( $rm_command );
putenv("TARGET=");

でも、全部エスケープしろという無茶ルールに出会った苦い思い出がありまして。rm_rf はその時書きました。

べつにプログラム内部で作ってる文字列ならエスケープ不要よね?

tmpname で作った文字列までエスケープさせられてやり切れない苦い思い。

PHPってアレゲプログラマが多い世界なので、shell injection を生みかねない。」

このような前提にたってフールプルーフなんだろうけど。ソコまでやるかって感じはある。

コード作成者を馬鹿にしやがってという悔しさ。

チェックするならコミット側とテストでチェックすればいいじゃん。

シェル呼び出しで済む作業をプログラム書いてそのテストコード迄書く作業に、何の意味があるのだろうか

などと叫んだけど、ルールはルールだからで終ったとに、週明けには派遣先に私の席がなかった。うん。

良くわからないセキュリティ・ヤクザが監査に入って system 関数を全部エスケープしろだのツマラナイ単純置換やらされた辛い記憶がよみがえる。

「tmp に、自動生成画像まとめたzip ファイルの削除でエスケープは無いわと思った記憶。」

phpの案件は闇が深い。

php で create temporary Directory(tmp)

create temp dir for zip unpacking

<?php
function tempDir($prefix = "php-temp"){

  $tmp_file_name= tempnam(sys_get_temp_dir(), $prefix );
  @unlink($tmp_file_name);
  @mkdir($tmp_file_name);
  return $tmp_file_name;

}

php で一時ディレクトリを作るのは面倒くさいんだよね。

面倒くさいんだよね。関数が用意されてない。 sys_get_temp_dir だとシステム標準の一時ディレクトリは取れるが、一時ディレクトリを作れない。

なので、しかたないので、tempname 関数で一時ファイルを作っておいて、ファイル消し、同名でディレクトリを作成する。

tempnam があるので救われた。

クラスの $thisを省略したい

$this->varname->method(); が書きにくい。

省略するには、カレントのスコープに変数展開をする必要がある。

<?php
//略
    extract(get_object_vars($this));

副作用があるとしたら、関数の引数と衝突してしまう。

関数の引数と衝突しないようにするには

<?php
//略
    extract( array_merge ( get_object_vars($this) , func_get_args());

などとする必要があります。長いなコレ。

しかも、代入が出来ない。困る。

php は this の省略が出来ない。悲しい

java などオブジェクトを作ればthis を省略できるんだけど。

//java
public class Test{
  public String name;
  public Test() {
    name="takuya";
  }
  public String greeting(){
    return  "「"+name+"」 ";//this省略
  }
}

php だとエラー

<?php
class Test{
  public $name;
  function __construct(){
      $this->name = "takuya"; // this 省略できない。
  }
  function greeting(){
    echo "{$name}"; // this 省略するとエラー

  }
}

しかたないので、 get_object_var して extractする

<?php
class Test{
  public $name;
  function __construct(){
      $this->name = "takuya"; // this 省略できない。
  }
  function greeting(){
    extract( array_merge ( get_object_vars($this) , func_get_args());
    echo "{$name}"; // $name がカレントスコープに展開される.
    $this->name = "john" ;// 代入が出来ない

  }
}

毎回書くの面倒くさいけどね。エディタのfunction () テンプレにでも仕込んでおけばなんとかなりそうだ。

call で全ての関数呼び出しを上書きしてもイイんだけど、それも面倒くさいんだよね。call は未知のメソッド呼び出しにしか使えないし。

読み込みのためだけに、extract ってのは、コードがグチャグチャになるので、あんまり進められた方法じゃないですね。