ppBlog Notice: LINE 148 of log.php: Uninitialized string offset: 4

ppBlog official

[ Tags :: PHP ]

短縮URLの元を知る

category-icon

 おはようございます、martinです。WC、初戦勝ちましたねぇ。正直期待していなかっただけに喜びも倍増といったところ。決勝トーナメント進出!なんて日が来るのでしょうか。

 さて、今回は前回のアクセス解析の続きみたいなものです。前回のエントリーで、短縮URLの元を知るサイトとして、http://knowurl.com/Link を紹介しましたが、他にもいくつかありますね。LongURLLink なんかもそうです。LongURLは、Firefoxの拡張版Link もあるようですね。APILink も公開されているようでjQueryのプラグインとかもあるようです。APIがあるんで、ppBlogでも使える様なJavaScriptを書いても良いですが、仕組みは結構単純なので、外部のAPIに頼らずともppBlogのみで完結できそうです。

 まずは、短縮URLがどのような仕組みになっているのか知る必要があります。短縮URLを提供しているサイトはいくつもあります(現時点で動いているのは bit.ly、j.mp、cli.gs、Short.ie、Idek.net、is.gd、sn.im、u.nuあたり)が、これら殆どのサイトでやっていることはリダイレクトです。PHPを使えば、その辺りの情報は簡単に取得出来ます。例えば、http://bit.ly/aKhZ1GLink は、http://p2b.jp/201006-get-html5-fileuploading-moduleというリンクの短縮形ですが、PHP経由でアクセスしてみると、リダイレクト先の情報などが入手出来ます。PHP5であれば、get_headers()Link 関数が使えます。便利ですね。この関数を使って以下を実行すると、

<?php
$url = 'http://bit.ly/aKhZ1G';
print_r(get_headers($url, 1));
?>
大まかには、以下のようになります。
Array(
 [0] => HTTP/1.1 301 Moved  /* Permanentlyと続くこともある */
 [Location] => http://p2b.jp/201006-get-html5-fileuploading-module /* リダイレクト先がある! */
 [MIME-Version] => 1.0
 [Content-Length] => 313
 [X-Powered-By] => PHP/5.1.6
)
[Location]の項目に短縮URLの元リンクが収められていますね。なので、配列からこれを取り出せばOKです。じゃPHP5ではないサーバーではどうするか。fsockopen()関数Link を使います。以下のような記述で行けるでしょう。
$url = 'http://bit.ly/aKhZ1G';
$_url = parse_url($url);
$port = isset($_url['port']) ? $_url['port'] : 80;
$host = isset($_url['host']) ? $_url['host'] : '';
$path = (isset($_url['path']) ? $_url['path'] : '/').(isset($_url['query']) ? '?'.$_url['query'] : '');
$request  = "GET ".$path." HTTP/1.1¥r¥n";
$request .= "Host: ".$host."¥r¥n";
$request .= "Connection: Close¥r¥n¥r¥n";

if($fp = fsockopen($host, $port, $errno, $errstr, $timeout=3)){
  stream_set_timeout($fp, 3);
  $ret = '';
  fputs($fp, $request);
  do {
   $ret .= fgets ($fp, 4096);
  } while (strpos($ret, "¥r¥n¥r¥n") === FALSE); // ヘッダー部分で十分
  fclose($fp);
}

これを実行すると、以下のような感じになります。

HTTP/1.1 301 Moved
Server: xxxx/0.7.42
Date: Tue, 15 Jun 2010 02:46:59 GMT
Content-Type: text/html; charset=utf-8
Connection: close
Set-Cookie:xxxx
Location: http://p2b.jp/201006-get-html5-fileuploading-module /* これが欲しい */
MIME-Version: 1.0
Content-Length: 313

これから、Location:の部分を取り出す正規表現は、以下のような感じでしょうか。

$redirectURL = preg_replace('{^.+?Location:¥s([^¥n]+?)¥n.+$}s', '$1', $ret);
これで、$redirectURLにhttp://p2b.jp/201006-get-html5-fileuploading-moduleという文字列が入ることになります。

 以上のことをやると、リダイレクト先が分かるのでppBlogのアクセス解析に組み込んでみました。「リンク元」の項目で、短縮URLっぽいものには、下のショットにあるように「expand」というアイコンみたいなやつが付くようになります。

shot1
短縮URLなので一体どこへのリンクなのか分からない

 そしてこれをクリックすると、Ajax経由で情報をゲットして以下のような表示に変わります。

shot2
その場でリダイレクト先のアドレスが表示される

 リダイレクト先があれば、これがその場で表示されます。これはリンクになっていますが、そのサイトへのリンクではなくて、グーグルでそのリンクを調べるようになっています。それで怪しげなサイトであればブラウザでアクセスするのを避けることが出来るわけです。

 ちなみに、Ajax部分は、以下のような関数で実現しています。思ったよりシンプルに出来ました:)

  var expand = function(url){
   var target = o(oParts.evt.target);
   var loader = oParts.create('IMG').src('../Images/loader.gif'); /* ローディングアニメーション */
   target.addAfter(loader);
   oParts.server.get('view.php?expand=' + url, function(ret){ /* これがAjax部分 */
    loader.away();
    if(ret == url){
     target.css('color:gray; cursor: default').html('redirect 0').title('リダイレクトはありません').on('click', function(){});
    } else {
     target.css('color:crimson; border-color: green').html('Redirect: <span onclick="googleIt(¥''+ret+'¥')" title="グーグルで検索">' + ret + '</span>');
    }
   });
  }

 一応、これを実現するためのview.php添付しておきますstatディレクトリの既存のやつと置き換えればOKかと思います。前回添付したものの上位版になります。

 今週末にppBlogの最新版配布を予定していますが、これはそのバージョンに組み込み予定です。

 


— posted by martin at 12:24 pm   commentComment [2]  pingTrackBack [0]

HTML5によるファイルアップロードスクリプトの配布

category-icon

 おはようございます、martinです。前々回ぐらいに、HTML5を用いたプログレスバー付きのファイルアップロードのデモを示しました。この手のスクリプトは、プログレスバーの表示にFlashやJavaを用いていることが多いのですが、ファイルサイズが大きくなる傾向になったり、設置がややこしかったりします。

 何件かソース希望のリクエストがあったので、ppBlogからのスピンアウトとして配布しようと思います。配布するやつは、PHPとJavaScript(+CSS)だけでプログレスバーを実現していて、設置も比較的簡単ではないでしょうか。添付ファイルを展開すると以下のファイルが含まれています。

  • index.html(ここにアクセス)
  • fileUpload.php(PHPでのファイルアップロード処理用)
  • oParts.js(プログレスバーのためのJSライブラリ)
  • progressbar.png(プログレスバーの画像)
  • PIX(アップロードした画像を保存するフォルダ)

 基本的には、展開したフォルダを然るべき場所にまるごとアップロードして、index.htmlにアクセスすればOKかなと思います。サーバーによっては、PIXディレクトリのパーミッションの指定が必要かもしれません(707とか)。

 画像を保存するディレクトリは、PIXにしていますが、これは適当に名前を変えても良いでしょう。fileUpload.phpの最初の方で指定出来ます。

$pix_dir = 'PIX/'; // 画像を保存するディレクトリ。パーミッションは707とか。

 うまく動けば、アップロード中は以下のような画面になっているかと思います。

shot

*あくまでサンプルです。最低限の実装なので、セキュリティ関連は、各自でいじって下さい。JavaScriptをいじれば、プログレスバーに加えて、全体の何パーセントが完了みたいなことも出来るでしょう。

添付ファイル: MultipleFileUpload.zipattachedIcon 

     


— posted by martin at 02:29 pm   commentComment [0]  pingTrackBack [1]

HTML5による複数ファイルアップロード

category-icon

 こんばんは、martinです。以前、Flex(Flash)を用いた複数ファイルのアップローダーLink を紹介しましたが、実はHTML5だけで出来るのになぁ、と思っていました。現時点で、IE8を除く主要なブラウザでは軒並み、HTML5のINPUT要素に対するmultiple属性に対応しているので、それによる実装をppBlogに施してみました。複数ファイルを選択可能にするには、input要素にmultipleを指定するだけです。

<input type="file" name="src[]" id="src" multiple />

 とりあえず実装してみただけですが、きちんと動作しました(ここのエントリーLink は画像を複数枚一度にアップロードした)。UIをどうするかで試行錯誤しましたが、プロトタイプにしてはまぁまぁかなと思っています。

shot1
このように一度に複数画像の選択が可能です。

 さて、複数の(画像)ファイルがアップロード出来るようになると、アップロードする枚数に応じて、サーバーにデータを渡す間、じっと待たされるようになります。現状、HTML5のみではぼーっと待つしかありません(-o-) なので、アップロードの進捗状況を示すプログレスバーが欲しくなります。この手のスクリプトはウェブ上にいろいろありますが、どれもFlashを用いたり、Perl(+JavaScript)を用いたりしたものです。出来ればPHP(+JavaScript)のみで完結させたい。

 いろいろ調べてみると、PHPとJavaScriptのみでは、ファイルアップロードに伴なうプログレスバーのギミックを提供するのは無理という記述ばかりです。というのもPHPには、ファイルアップロードの途中経過を知らせる仕組みが備わっていないからです。実は、PHP5.2以上であれば、PECL APC拡張機能を組み込んで可能Link なのですが、サーバー側で PECL APCエクステンションをインストールする必要があり、これはレンタルザーバー等では敷居が高いでしょう。

 なので(Perlはあまり好きになれないという理由もあり)PHPとJavaScriptのみによる実装を考えてみました。まずは、PHPにおける、POST メソッドによるファイルアップロード時の挙動を知る必要があります。マニュアルによれば、基本的に以下の手順を踏みます。
  1. サーバー上に転送される(画像)データは、最初は一時的なディレクトリ(テンポラリディレクトリ)にアップロードされます。この一時的なディレクトリは、だいたい/tmpディレクトリのことが多いです。php.iniで指定可。
  2. 画像データの転送が無事に終わると、move_uploaded_file関数を用いて指定したディレクトリに画像データを移動させます。

 PHPでのネックは、この1番目の進捗状況を知るメソッドが備わっていないことです(なのでこの部分だけはPerlで処理するスクリプトがある)。サーバーサイドで提供しないのであれば、こちらからゲットしに行きましょう。アップロード中のデータは、テンポラリディレクトリに溜まっていくので、そのディレクトリのサイズは徐々に大きくなるはずです。なので、そのディレクトリのサイズを定期的に監視すればOKということになります。この「定期的に監視」という部分にJavaScriptのAjaxを使えば良いわけです。

 ディレクトリのサイズは、以下の記述で取得可能です。
$tmp_dir = '/tmp'; // 取得したいテンポラリディレクトリ

$size = 0; // ディレクトリのサイズ

$d = opendir($tmp_dir);
while($file = readdir ($d)){
 if(is_file($tmp_dir.'/'.$file)){
  $size += filesize($tmp_dir.'/'.$file);
 }
}
closedir($d);
echo($size); // ディレクトリの合計サイズを得る

 なお、上の例では、テンポラリディレクトリは/tmpですが、これを取得したい場合は、ファイルアップロード時に現れる変数の$_FILES['src']['tmp_name']を利用して、

dirname($_FILES['src']['tmp_name']);

で取得可能です。

 あとは、AjaxとPHPで、このディレクトリサイズを返すような記述をして、それをJavaScript側に渡し、プログレスバーっぽく見せればOKとなります。具体的なデモLink を見てみましょう。うまく行けば、転送中のブラウザ画面は下のようなスクリーンショットになります。Firefox3.6.3Safari, Google Chromeの最新版で動くと思います。

progressbar
プログレスバーが表示され、進行状況が一目瞭然。

       


— posted by martin at 01:14 am   commentComment [6]  pingTrackBack [0]

Flexを用いた複数ファイルアップロード

category-icon

 こんばんは、martinです。前回のエントリーで述べていたように、次期バージョン(v1.9.0)では、画像ファイルのアップロードの際に、複数の画像をまとめてアップロードできる仕組みを提供予定です。

 現状では、複数の画像を一度にアップロードするには、FlashかJavaを使うしかありません。JavaもFlashも素人ですが、とっつきやすいのはFlashですし、ファイルアップロードに関しては、色んなサイトでソースコード付きのFlash/Flexのデモサイトがあったので、Flexを用いたインターフェイスを作ってみました。

実際に試すことが出来るデモサイトLink

 実際には、Coding CowboysLink というサイトにあったプログラムをベースに、好みのインターフェイスになるよういじっただけです。

uploadInterface
改良したインターフェイス。日本語化したりとか。

 ローカルのフォルダからは基本的に任意のファイルを選べるのですが、画像ファイル(*.jpg, *.png, *.gif)のみに絞っています。また、Flexの練習もかねて、デモページのFlashではアップロードした画像を見ることが出来るように、右下に画像ギャラリーへのリンクボタンを付けてます。

画像ギャラリーへのリンクLink

 ちなみに、このリンク先の画像ギャラリーは、Flashとは関係なしに、単にPHPでページを生成しています。CSSのみを用いたシンプルなものです。IE向けのハックは使ってませんが、IE6でもそう表示が崩れることはないかなと期待。アップロードされた画像ファイルの内、最新のJPEG画像を5枚表示するようにしてます。

galleryShot
CSSのみでのフォトギャラリー。IE6でも何とか動くかな。

 今後、いじるとすれば、ファイルサイズ上限を指定したりとかですかね。とりあえず。

     


— posted by martin at 04:10 am   commentComment [8]  pingTrackBack [0]

array_shiftとreset

category-icon

 こんばんは、martinです。ppBlogでは、「軽快な動作」を常に念頭において開発しています。PHPには、実に様々な関数が最初から提供されていて、似たような振る舞いをする関数も結構あります。なので、こういう場合は、それぞれの関数で処理時間を計測して、より処理速度が速いほうを採用するようにしていますが、最近、そんなやつをひとつ見つけました。

 ppBlogでは、内部でいろんな配列が定義されていて、それを切ったり貼ったりして使用してます。その際に、配列の先頭の要素を取り出すという処理を至る所でしているのですが、これまではarray_shiftを用いていました(というかそれしか知らなかった)。

 

array_shift() は、array の最初の値を取り出して返します。配列 array は、要素一つ分だけ短くなり、全ての要素は前にずれます。 数値添字の配列のキーはゼロから順に新たに振りなおされますが、 リテラルのキーはそのままになります

引用元: PHP: array_shift - ManualLink
 上の赤字にあるように、元の配列を変えてしまうという点に留意していれば、便利な関数です。で、最近別の似た振る舞いをする関数を見つけました。reset()関数です。

reset() は、array の内部ポインタの先頭の要素に戻し、配列の最初の要素の値を返します

引用元: PHP: reset - ManualLink

 何となく、内部ポインタを先頭に移すんだなという印象でファイルオープンfopen()などを使う場面ぐらいでしか使わないと思っていたのですが、その要素も返すんですね。

<?php
$stack = array("orange", "banana", "apple", "raspberry");
$fruit = array_shift($stack); // 結果はorange
 // $stackはarray("banana", "apple", "raspberry")になる
?>
<?php
$stack = array("orange", "banana", "apple", "raspberry");
$fruit = reset($stack); // 結果はorange、$stackは元のまま
?>

 さてどちらが処理速度が速いかというと、ローカルな環境(PHP5.2.9)では、実はそんなに変わりません。100万回の試行で、前者が3.4秒のところが後者のreset()関数だと3.2秒と、ちょっとだけ速いかなという感じです。でもタイピングも少なくて済むし、こういうのの積み重ねが大事なので、今後はreset()を使うようにしようと思います。余談ですが、ラズベリー(raspberry)の綴りはちょっと意外でした。

 ここでひとつ押さえておくべきことは、上の$stackの例のように、もし配列のキーが定義されていない、つまりキーインデックスがゼロから始まるような配列ならば、わざわざ関数を持ち出さなくても、
<?php
$stack = array("orange", "banana", "apple", "raspberry");
$fruit = $stack[0]; // 結果はorange、$stackは元のまま
?>
でこと足りるということです(これだと100万回の試行では2.4秒と最速)。これで済む場合はそうしますが、ppBlogの内部では、
Array
(
     [3] => orange
    [11] => banana
    [23] => apple
    [29] => raspberry
)
みたいに、キーの添え字にも意味がある処理が多いです。

 

— posted by martin at 06:36 pm   commentComment [0]  pingTrackBack [0]

T: Y: ALL: Online:
Created in 0.0062 sec.
prev
2024.10
next
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31