July 20, 2014

Goutteでダウンロードしたファイルの内容を取得する

PHPのスクレイピングライブラリで有名なGoutte https://github.com/fabpot/Goutte で、ダウンロードしたファイルの内容を取得する手順メモです。

Goutteをインストールします。
$ composer require fabpot/goutte:2.*
以下、ファイルをダウンロードするサンプルです。
<?php

require_once './vendor/autoload.php';

// Goutte\Client のインスタンスを生成する
$client = new Goutte\Client;

// ダウンロードしたいファイルがあるURLにアクセスする
$client->request('GET', 'http://example.com/download.php');

// レスポンスのオブジェクトを取得する
/** @var Symfony\Component\BrowserKit\Response $response */
$response = $client->getResponse();

// コンテンツのオブジェクトを取得する
/** @var GuzzleHttp\Stream\Stream $content */
$content = $response->getContent();

// seek(0) して getContents() するとファイル内容を取得できる
$content->seek(0);
echo $content->getContents();
これで、ダウンロードしたファイルの内容を取得出来ました。ポイントは seek(0) です。これをしないと、どうにも取得できませんでした。

尚、ダウンロードさせる側に、以下のPHPファイルを置いて確認しました。
<?php

// download.txt は別途用意する
$file = 'download.txt';
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$file);
header('Content-Length: ' . filesize($file));
readfile($file);

July 17, 2014

Piwikのメンテナンスモードを切り替えるプラグインを作りました

2014-07-18 追記:
Packagistに登録したので、Composerで簡単にインストールできるようになりました。
https://packagist.org/packages/mamor/piwik-plugins-maintenance

--

前回 http://madroom-project.blogspot.jp/2014/07/piwik.html の続きです。

というわけで、出来ました。
https://github.com/mamor/piwik-plugins-maintenance

どうも Piwik Plugins Marketplace http://plugins.piwik.org/ に反映されないので、インストール方法と使い方をメモしておきます。

1.
上記のソース一式を /path/to/piwik/plugins/Maintenance として配置します。

2.
Maintenanceプラグインを有効にします。たぶん画面からできますが config/config.ini.php に以下を追記してもOKでした。
[Plugins]
Plugins[] = "Maintenance"

[PluginsInstalled]
PluginsInstalled[] = "Maintenance"
3.
有効になったか確認します。
$ ./path/to/piwik/console
maintenance
  maintenance:off                        Disable Maintenance Mode.
  maintenance:on                         Enable Maintenance Mode.
4.
実行してみます。
$ ./path/to/piwik/console maintenance:on
Now, Maintenance Mode is 1.

$ ./path/to/piwik/console maintenance:off
Now, Maintenance Mode is 0.
config/config.ini.phpを書き換えるので、書き込み権限には注意して下さい。

Piwikのプラグインを作るメモ

Piwikのメンテナンスモードをコマンドラインから切り替えたいのですが、標準では備わっていないようなので作ってみようと思います。

出来上がったらPiwik Plugins Marketplaceで公開する予定です。
http://plugins.piwik.org/
http://developer.piwik.org/guides/distributing-your-plugin

以下、必要なファイルを生成する手順のメモです。
# プラグインを作成します
$ ./console generate:plugin

# プラグインの名前を入力します
Enter a plugin name: maintenance

# プラグインの説明を入力します
Enter a plugin description: Allows you to manage maintenance mode by CLI.

# プラグインのバージョンを入力します
Enter a plugin version number (default to 0.1.0):

# 併せてAPIとControllerを作成するか入力します
Shall we also create an API and a Controller? (y/N)N

# コマンドを作成します
$ ./console generate:command

# 先ほど作成したプラグインを選択します
Enter the name of your plugin: Maintenance

# コマンド名を入力します
# この場合は "./path/to/piwik/console maintenance:on" になります
Enter the name of the command: on

プラグインを有効にした後 plugins/Maintenance/Commands/On.php を好きに編集します。

July 10, 2014

PHP5.5 で "continue 2" したらメモリ使用量が増えた

PHP5.5 で "continue 2" したらメモリ使用量が増えている気がしたので、簡単に検証してみました。

使ったソースは以下です。
<?php

/**
 * メモリ使用量をKB表記で返す
 *
 * @return string
 */
function peak_usage() {
    return (memory_get_peak_usage(true) / 1024).'KB'.PHP_EOL;
}

// 100要素数の配列を作る
// 各要素には ['a', 'b', 'c'] が入る
$array = [];
for($i = 0; $i < 100; $i++) {
    $array[] = ['a', 'b', 'c'];
}

// もう一つ適当に配列を作る
$array2 = ['x' => 'X', 'y' => 'Y'];

// $array * $array2 を反復を 100 回行う
// $array * $array2 の反復の中で即時 continue 2 する
for($i = 0; $i < 100; $i++) {
    if ($i % 10 === 0) {
        echo php_sapi_name() === 'cli' ? peak_usage() : nl2br(peak_usage());
    }

    foreach ($array as $key => $value) {
        foreach ($array2 as $key2 => $value2) {
            continue 2;
        }
    }
}
まずは、PHP 5.4 (OS X Mavericks) で確認してみます。
$ php -v
PHP 5.4.24 (cli) (built: Jan 19 2014 21:32:15)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
ブラウザからアクセス (ビルトインサーバーで実行)
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
コマンドラインから実行
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
結果に違いはありませんでした。

次に、PHP 5.5 (Vagrant x Ubuntu 13.10) で確認してみます。
$ php -v
PHP 5.5.12-2+deb.sury.org~saucy+1 (cli) (built: May 12 2014 13:45:47)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    with Xdebug v2.2.3, Copyright (c) 2002-2013, by Derick Rethans
    with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies

$ apache2 -v
Server version: Apache/2.4.9 (Ubuntu)
Server built:   Apr  1 2014 08:58:43
ブラウザからアクセスした結果 (Apacheで実行)
512KB
768KB
1280KB
1536KB
2048KB
2304KB
2816KB
3072KB
3584KB
3840KB
コマンドラインから実行した結果
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
ブラウザからアクセスした時に、かなり増えました。ちなみに "continue 2" の箇所をコメントアウトすると、ブラウザからアクセスした時も、ずっと "512KB" のままになりました。

Stack Overflowに以下の投稿が見つかり、"Zend OPcache"に関することが書かれています。
http://stackoverflow.com/questions/23231675/php-5-5-memory-leak-when-using-continue-2-inside-two-foreach-loops

2014-07-11 追記: PHP本家にも報告されていました。
https://bugs.php.net/bug.php?id=67111

再現条件は良くわかりませんが、Zend OPcacheのバグっぽいですね。

尚、foreach()している箇所をwhile()に変えたら、増加は発生せず、ずっと"512KB"となりました。応急処置するなら、この方法ですかねぇ。
reset($array);
while (list($key, $value) = each($array)) {
    reset($array2);
    while (list($key2, $value2) = each($array2)) {
        continue 2;
    }
}

July 3, 2014

PHPで2箇所の緯度経度から距離を計測するメモ

メモです。

MySQLのgeometry型とかは使用せず、以下のライブラリを用いてPHPだけで、多摩センターと新宿の距離を測ってみます。
https://github.com/mjaschen/phpgeo
(README.mdに書いてある通りですが。。。)

答え合わせには、以下を使わせて頂きました。
http://www.kyori.jp/

ライブラリをインストールして、適当なPHPを書きます。
$ composer require mjaschen/phpgeo:0.*
<?php

require_once 'vendor/autoload.php';

use Location\Coordinate;
use Location\Distance\Vincenty;

// 多摩センター
$coordinate1 = new Coordinate(35.623891, 139.42287299999998);

// 新宿
$coordinate2 = new Coordinate(35.6938401, 139.70354940000004);

echo $coordinate1->getDistance($coordinate2, new Vincenty());
"26573.928" (メートル)が出力されました。問題無さそう。