‘解決’ カテゴリーのアーカイブ

html5uploaderで複数アップロード時のバグ修正

Gmailのようなドラッグアンドドロップでファイルをアップロードする機能が使いたかったので探していたところ、見つけたのがhtml5uploaderです。JSと、サーバーサイドのPHPが付いてます。

html5uploader

デモ
http://www.weeby.pl/blog/html5uploader/uploader.html

比較的簡単な構造で最低限のアップロード機能を実装しているので、elFinderと組み合わせて使うことにしました。

で、表題のバグですが、複数のファイルを同時にアップロードすることはできるのですが、時々サーバからNo file to uploadというメッセージが返ってくることがあります。リクエストを見ると、送るはずのContent-Lengthが0バイトで、データを送信していないようです。

原因はonloadendイベントの関数でreaderオブジェクトを直接呼び出して使ってるからですね。というわけで修正。

// Once the process of reading file
this.loadEnd = function() {
	bin = reader.result;

// Once the process of reading file
this.loadEnd = function() {
	bin = event.target.result;

に修正して完了です。

Pluploadの方が高性能かつソースもきれいでよく出来てるのですが、GPLなんですよね。コマーシャルライセンスは10ユーロなんで良心的で安いんですが。今回はファイルマネージャーに統合しちゃいたかったので、小型のhtml5uploaderにしてみました。

elFinderがDnDのアップロードに対応しないかなぁ。


A cache key must contain both a module and an action parameter

Symfony 1.4にて、Flash上のリンクからページにリンクをしたところ、500エラーが発生。

A cache key must contain both a module and an action parameter

同じURLをそのまま別のウィンドウで開くと問題なく開けるので、リクエストを見比べたところ、違いはrefererの有無だけ。

エラーはinclude_partialの先で起きていて、調べていくと、パラメータを渡さないpartialに、config/cache.ymlでcontextual: trueとしていたのが問題でした。

falseにして解決。

ちなみにこのException自体も、本来は404を出すはずのところらしいです。

あと、キャッシュ有効にしないとこのエラーは出ません。


IP電話とUPnPとWZR-HP-G300NHの話

OCNのドットフォンを申し込んだので、さっそくセットアップ。

回線契約はフレッツネクスト。OCNドットフォン光を申し込むと送られてくる、VE-TA10という機器を使います。

すでに家の中にWZR-HP-G300NHでLANが構築されているので、スループットが不安なVE-TA10をルータモードにせずに、現状のWZR-HP-G300NH配下にVE-TA10を、アダプタモードとして接続しています。

配線構成図は以下のページのまま。

VE-TA10|IP電話の設定追加|OCN

で、電話機から自分の電話番号と市外局番を指定すれば良いだけなのですが、いくら設定しても、VE-TA10の「050IP電話」のLEDが点灯しません。消灯状態です。ちなみに設定方法は以下。

VE-TA10|IP電話の初期設定|OCN

「050IP電話」が有効にならない理由は、UPnPが利用できないから、ということらしいです。

UPnPが有効かどうかを簡単に調べるには、Windows Live Messengerを使って調べられます。メニューのツールから、オプションを開いて、接続ページの状況というところに、「非 UPnP ポート制限付きNAT(restricted)を経由してインターネットに接続しています。」と表示されていたら、UPnPが有効になっていません。メニューのツールが見つけられない場合は、Altキーを押すことでメニューが表示されます。

ちなみにUPnP調査ツールみたいなものは他にも色々あるとは思います。

で、UPnPは有効にしているはずなので、改めてWZR-HP-G300NHの設定画面で、UPnPの状態を確認してみると、確かに「UPnP機能」を「使用する」にチェックが入っています。設定メニューは、「ゲーム&アプリ」から、「UPnP」を選択すると表示されます。

で、先ほどのLive Messengerの状態から見るに、UPnPが有効ではないという状況のようです。調べてみると、このWZR-HP-G300NHというルータでは、UPnPを使用する設定にしてあっても、機能が無効になることがあるとのこと。

あれもこれも興味ありますねん!

上記のページの手順に従って、「UPnP機能」の「使用する」を一度チェックを外す。「設定」ボタンを押す→10秒ほど待機→もう一度チェックを入れる→12秒ほど待機、で見事につながるようになりました。Live Messengerの接続状況(一度Live Messengerを終了する必要があります)を確認すると、UPnPを利用して接続できている旨に、表示内容が変わります。

これで、IP電話も正常に接続できるようになりました。

ちなみにルータのファームウェアは1.74。2010年10月時点で最新です。もう更新されないんだろうなぁ…WZR-HP-G300NHは色々不安定です。無線など特に。注意しましょう。


symfonyで携帯端末用のテンプレート切り替えを実装する

symfony 1.4で、PCサイトの携帯版を作ることになりました。

アクションは共通にして、テンプレートのファイル名を、携帯とPCで切り分けるようにしたいと思います。

例:
templates/indexSuccess.php (PC用)
templates/indexSuccess.mobile.php (携帯用)

で、これはフォーマットを指定することで実現できます。フォーマットに関してはJobeetを参照。

Practical symfony | 15日目: Web サービス | symfony | Web PHP Framework

まずは携帯キャリアのIPから高速にキャリア判定をしてくれるプラグインを準備しておきます。

sfMobileIPPluginをsymfony 1.4で使ってみた

次にフィルタを用意します。

app/frontend/lib/filter/myMobileLayoutFilter.class.php

<?php

class myMobileLayoutFilter extends sfFilter
{
    public function execute($filterChain)
    {
        if ($this->isFirstCall()) {
            
            if (sfMobileIP::carrier() != 'pc') {
                $request = $this->getContext()->getRequest();
                $request->setRequestFormat('mobile');
            }
            
        }

        $filterChain->execute();
    }
}

最後にfilters.ymlを編集すればOKです。

app/frontend/config/filters.yml

rendering: ~
security:  ~

myMobileLayoutFilter:
  class: myMobileLayoutFilter

cache:     ~
execution: ~

layoutのテンプレートも携帯版を用意しておきます。

例:

app/frontend/templates/layout.php (PC用)

app/frontend/templates/layout.mobile.php (携帯用)

注意点として、partialなども全部「.mobile.php」の形式のファイルがないと動作しません。どこかでファイルを作り忘れるとsfRenderExceptionが投げられるので注意してください。ちなみに、dev環境だとそのまま真っ白な画面になってしまって、原因追求がしにくいようです。

その場合は、ログファイルにてチェックしましょう。

log/frontend_dev.log

symfony [err] {sfRenderException} The template "indexSuccess.mobile.php" does not exist or is unreadable in "".


Visual Studio 2005をWindows 7で使う

インストール自体は普通にできます。

インストール後、以下の2つのファイルを順番にインストールします。
SP1の方は431MBほどあるので注意。

ダウンロードの詳細 : Visual StudioR 2005 Team Suite SP1
ダウンロードの詳細 : VS2005 SP1 Update for Vista

あと、Visual Studio起動時に表示されるスタートページのニュースチャンネルは、該当URLがすでになくなっているので、スタートページ自体表示しないようにした方がいいかもしれません。

ツール→オプション→環境→スタートアップで。


sfMobileIPPluginをsymfony 1.4で使ってみた

sfMobileIPPluginという、IPベースで高速にキャリア判定をするsymfonyプラグインがあったので、使ってみました。

1.0用に作られているらしく、一部修正する必要があります。

とりあえずやってみてダメだった手順。

$ ./symfony plugin:add-channel openpear.org
$ ./symfony plugin:install -s beta openpear.org/sfMobileIPPlugin

ダウンロードしてインストールを試みる。(これもXMLがおかしいと言われて不可)

$ ./symfony plugin:install ./sfMobileIPPlugin-0.0.13.tgz

ダメっぽいので適当にディレクトリ作って解凍しました。これでセットアップできました。

$ mkdir tmp
$ mv sfMobileIPPlugin-0.0.13.tgz ./tmp/
$ cd tmp/
$ tar xvzf ./sfMobileIPPlugin-0.0.13.tgz
$ mv ./sfMobileIPPlugin-0.0.13 ../plugins/sfMobileIPPlugin

configのyml類はconfigディレクトリに移さずに使える模様です。configにコピーしておけばオーバーライドできるので開発環境の場合はconfigにコピーしたあと、ローカルのネットワーク範囲を追加しておけば便利かと思います。

手動で設置したので、ProjectConfigurationにプラグインを使用するように記述する必要があります。

config/ProjectConfiguration.class.phpの

public function setup()
{
  ...
}

$this->enablePlugins('sfMobileIPPlugin');

を追加します。

1.4ではすでに存在しないメソッドがあるので、それも書き換えます。

plugins/sfMobileIPPlugin/lib/sfMobileIP.class.php

static protected function configFile()
{
  $config_dir  = sfConfig::get('sf_config_dir_name');
  $config_file = $config_dir.DIRECTORY_SEPARATOR.'mobile_ips.yml';
  return sfConfigCache::getInstance()->checkConfig($config_file);
}

を以下のように修正。

static protected function configFile()
{
  return sfContext::getInstance()->getConfigCache()->checkConfig('config/mobile_ips.yml');
}

あと、pear::Net_IPv4が必要です。これがないとdev環境でもエラーを出さずに途中で止まります。

symfonyコマンドでもインストールできますが、pluginディレクトリが汚くなるので、オートロードできる場所にNet_IPv4.phpファイルを適当に設置すれば良いかと思います。

http://pear.php.net/package/Net_IPv4/download

あとは

./symfony cc

を実行して、プログラム内でsfMobileIP::carrier()を実行すればキャリアを読み取れます。


debian lennyにJDKをインストールする

aptでインストールできますが、non-freeパッケージを有効にする必要があります。

# vi /etc/apt/sources.list

末尾に1行追加します。

deb http://ftp.jp.debian.org/debian/ lenny non-free

# aptitude update

# aptitude install sun-java6-jdk
パッケージリストを読み込んでいます… 完了
依存関係ツリーを作成しています
状態情報を読み取っています… 完了
拡張状態情報を読み込んでいます
パッケージの状態を初期化しています… 完了
タスクの記述を読み込んでいます… 完了
以下の新規パッケージがインストールされます:
  avahi-daemon{a} dbus{a} dbus-x11{a} gsfonts{a} gsfonts-x11{a} java-common{a} libasound2{a}
  libavahi-common-data{a} libavahi-common3{a} libavahi-core5{a} libdaemon0{a} libdbus-1-3{a} libnss-mdns{a}
  libxi6{a} libxtst6{a} odbcinst1debian1{a} sun-java6-bin{a} sun-java6-jdk sun-java6-jre{a} unixodbc{a}
更新: 0 個、新規インストール: 20 個、削除: 0 個、保留: 0 個。
61.7MB のアーカイブを取得する必要があります。展開後に 175MB のディスク領域が新たに消費されます。
先に進みますか? [Y/n/?]

途中でライセンスの確認をされます。
問題なければ続行すれば後は勝手に進んでインストール完了です。


530 5.7.0 Must issue a STARTTLS command first.の対処

redmineをWindowsマシンにインストールして、通知メールをGmail(TLS)経由で送ろうとしたときにはまったエラーの対処法です。

手順は以下サイトを参考に。
Setup Redmine to send email using GMail – Redmine Blog – The Official Redmine blog –

redmineの管理設定画面上から、「テストメールを送信」をしたあと、

メール送信中にエラーが発生しました (530 5.7.0 Must issue a STARTTLS command first. ***************** )

というエラーが発生していました。

問題はaction_mailer_optional_tlsのインストールの失敗。

C:\>cd Rails\redmine-1.0.1
C:\Rails\redmine-1.0.1>ruby script/plugin install git://github.com/collectiveidea/action_mailer_optional_tls.git

何もエラーも表示されずに実行されるのですが、vendor\plugins\action_mailer_optional_tlsの中身が空の状態。

ということで、
collectiveidea’s action_mailer_optional_tls at master – GitHub
から、action_mailer_optional_tls以下のファイルをディレクトリ含めて一式ダウンロードして、手動で設置すればOKです。

あとはRedmineを再起動して再度送信テストをしてみてください。Apps経由でも使えるので便利ですね。

参考までに環境メモ。Windows XP SP3、Ruby 1.8.7  P248、gem 1.3.5でした。


phpMyAdminのYAMLエクスポートとsymfonyのfixture

Symfony 1.4+Doctrineにて。テストを実行するために、fixtureを用意するのですが、

$ symfony doctrine:data-dump dump.yml

でやろうとしたらデータが重すぎて途中で落ちる。

ので、phpMyAdminにYAMLエクスポート機能がいつの間にか実装されていたので、それを使って必要な部分だけをエクスポートします。

ところがそれをそのまま読み込むといくつか問題が…

ということで、気になった3点。

  • 改行があると読み込めない
  • 日付形式が読み込めない
  • fixtureのymlファイルよりインデントひとつ分浅い

改行のある行はダブルクォートで囲ってから、改行文字を\nにすれば読み込めるようになります。

日付はダブルクォートで囲めばOK。

インデントは置換するなり何なりしましょう。

テスト周りに関してはチートシートが欲しいなぁ…


Symfonyで外部のプログラムを実行する

Symfony 1.4でシェルのプログラムを呼び出すときに、PHPのexec関数に代わる便利なメソッドがあったのでメモ。

sfFilesystem::execute()がそれです。
symfony API » sfFilesystem Class | symfony | Web PHP Framework

内部的にはproc_openで
戻り値は、標準出力と標準エラー出力が分離されて配列で返ってきます。

タスクから、呼び出すとこんな感じになります。

    protected
        $outputBuffer = '';

    protected function execute($arguments = array(), $options = array())
    {
        // initialize the database connection
        $databaseManager = new sfDatabaseManager($this->configuration);
        $connection = $databaseManager->getDatabase($options['connection'] ? $options['connection'] : null)->getConnection();

        // 処理待ちリストから一行取得
        $process = Doctrine::getTable('Processes')->findOneByStatus('WAIT');
        $command = $process['command'];

        // バッファクリア
        $this->outputBuffer = '';
        try {
            // 実行。第二引数は標準出力、第三引数は標準エラー出力を受け取るコールバック関数
            list($output, $err) = $this->getFilesystem()->execute($command, array($this, 'setBuffer'), array($this, 'setBuffer'));
            $process['status'] = 'SUCCESS';
            $process['message'] = $output;
            $process->save();
        } catch (RuntimeException $e) {
            // コマンドが実行できなかった場合と、終了時エラーの場合はRuntimeExceptionがthrowされる
            $process['status'] = 'FAILED';
            // エラー時はexecuteの戻り値を取得できないのでコールバックの結果からメッセージを取得
            $process['message'] = $this->outputBuffer;
            // 必要なら$e->getCode();でエラーコード取得できます
            $process->save();
        }
    }

    public function setBuffer($output)
    {
        $this->outputBuffer .= $output;
    }

/vendor/pear/php/symfony/task/project/sfProjectDeployTask.class.phpがサンプルとして使えます。

もちろん、PHPのexec関数を使って

exec($command, $output = array(), $return_var = 0);

とかしてもいいと思います。

多分プラグインのインストール段階でmakeとかするときに使うんじゃないですかね。

標準出力を段階的に画面に表示できるので。

ただし、出力バッファの読み取り単位ごとに、0.1秒のディレイをかけているようなので、速度重視なところでは注意が必要です。