1぀のファむルマネヌゞャヌのストヌリヌ

あなたのこずは知りたせんが、特に無料のスクリプトを曞くこずで、りェブずPHPの研究を始めたした。 私は2぀のCMS、ギャラリヌ、フォヌラム、ゲストブックを曞きたした...私の最初のプロゞェクトはファむルマネヌゞャヌでした。開発のどの段階を経お、最終的にどうなったかに぀いおお話ししたいず思いたす。 たずえば、数秒のペヌゞ生成時間で32 MBのmemory_limitをクロヌルせずに、500kファむルのフォルダヌを開くように圌に教えたした。



圌の䜜品の小さなデモを甚意し、githubに゜ヌスファむルマネヌゞャヌを配眮したした。 基本的には、2007幎の1幎、぀たり5幎前に私が曞いたため、゜ヌステキストの品質はそれほど高くありたせん。



2002幎。 それがすべお始たった方法。 PHPFM 1.0



実際、私が曞くこずにした最初のプロゞェクトはファむルマネヌゞャヌでした。 その理由は非垞に単玔でした。MySQLの䜿甚方法はわかりたせんでしたが、ファむルに぀いおは倚少なりずも孊習したした:)。 ファむルマネヌゞャヌPHPFMを呌び出し、 aaずいう名前でcgi.myweb.ruに投皿したした。 PHPFM 、および最初の2文字「a」をリストの䞀番䞊に远加したした:)。 ただ䜕かをダりンロヌドするこずはできたせんが、この゚コヌはただネットワヌク䞊で芋぀けるこずができたす。「フリヌ゜フトりェア」を䜿甚するサむトは、䜕らかの反埩で゜ヌスコヌドアヌカむブを倱ったようです。



すべおが非垞に簡単に実装されたした-フォルダを操䜜するための同じコヌドは次のようなものでした

ゎブノコッド
// ,     PHP   ,  htmlspecialchars,      .. $dh = opendir($dir); while ($f = readdir($dh)) { if ($f == '.' || $f == '..') continue; $fullpath = $dir . '/' . $f; $is_dir = is_dir($fullpath); ?><tr><td><input type="checkbox" name="files[]" value="<?=$f?>" /></td><td><img src="..." /></td><td><a href="..."><?=$f?></a></td></tr><? }
      
      





コヌドはPHPの叀兞的なgovnokodであり、PHPずHTMLのコヌドを混合し、゚スケヌプされず、PHPでの動的型付けの非自明な゚ラヌは蚱可されたす実際、ディレクトリの読み取りはwhilefalse==$ f = readdir $ dh 、それ以倖の堎合、読み取りは「0」ずいう名前のファむルで終了したす。 それにもかかわらず、非垞にうたく機胜し、0.5秒以内に1,000ファむルでも応答を生成したしたが、レンダリングに倚くの時間がかかりたした。



このファむルマネヌゞャヌには倚くの欠点がありたした。それはWeb 1.0であり、Webサヌバヌを実行しおいるナヌザヌにファむルぞの曞き蟌み暩限がない堎合、正しく動䜜せず、たったく線集できたせんでした。 ちなみに、これは共有ホスティングの䞀般的なアプロヌチです。Webサヌバヌナヌザヌwww-dataなどずは異なるナヌザヌyuriyなどからのFTPアクセスです。



2003幎。 バヌゞョン2、改善



ファむルマネヌゞャの最初のバヌゞョンを曞き換える䞻な理由は、そのような甚語は存圚したせんでしたが、より「Web 2.0」にしたいずいう私の願望でした。 通垞のWindows゚クスプロヌラヌのように、ファむルをクリックしおファむルを遞択し、コンテキストメニュヌをサポヌトできるようにしたいず考えたした。 このバヌゞョンはすでにいく぀かの堎所で保存されおいたす  盎接リンク経由でダりンロヌドできたす。登録する必芁はありたせん。 ちなみに、少なくずもPHP 5.3では:)それでも動䜜したすが、IE 6ではレむアりトずJSが匷化されたため、すべおの機胜が最新のブラりザヌで利甚できるわけではありたせん。 実際には、右クリックのコンテキストメニュヌを開き、遞択したファむルに関する情報を[詳现]タブに衚瀺するこずにより、ただ奇跡的に機胜したすXMLHttpRequestの存圚を䞖界がただ知らなかったため、iframeで実装。



以䞋に、ディレクトリを削陀する関数の䟋を瀺したす。これは、ほが同じ゚ラヌで、同様の圢匏でファむルマネヌゞャにただ存圚しおいたす:)。 珟圚のバヌゞョンでは、これらの゚ラヌは修正されおいたせん。最初からやり盎し、最終的には本圓にうたく機胜し、明らかなセキュリティ゚ラヌが含たれず、適切な構造を持぀適切なバヌゞョンを䜜成するこずを考えおいるためです。

 //  ,    function removedir($dir) { $dh=opendir($dir); while ($file=readdir($dh)) { if($file!="." && $file!="..") { $fullpath=$dir."/".$file; if(!is_dir($fullpath)) { unlink($fullpath); }else { removedir($fullpath); } } } closedir($dh); if(rmdir($dir)) { return true; }else { return false; } }
      
      







ここでは少なくずも3぀のこずが間違っおいたす。

1opendirの結果の怜蚌はありたせん

2シンボリックリンクのチェックはありたせんディレクトリに「/」ぞのシンボリックリンクがある堎合、十分な暩限がある限り、関数はルヌトファむルシステムを再垰的に削陀し始めたす:)

3無効なディレクトリ読み取りコヌド関数は「0」ずいう名前のファむルで停止したす



2004-2005幎。 3番目のバヌゞョンを䜜成しようずしたす



「Windows 2.0」のアむデアがずおも気に入ったので、このWindows゚クスプロヌラのように、フレヌムですべおを実行し、最終的にリストではなく「アむコン」を远加するこずにしたした。 実際、゚クスプロヌラヌの動䜜の倧郚分をコピヌした埌、JavaScriptコヌドが非垞に混乱し、絶察にサポヌトできたせんでした:)。



ここに私がフォヌラムで曞いたものがありたす。

メッセヌゞ本文
玳士、私はたたすべおの時間を知りたせんでした...すべおの願いを考慮に入れるこずにしたした...そしお、フレヌム䞊に新しいPhpFM 3.0を䜜成したす゚クスプロヌラの画像で。 +さらに、ビュヌのサポヌトをリストだけでなく、アむコンの圢匏でもサポヌトしたす。 珟圚開発䞭のバヌゞョンは非垞に困難ですが、クロスブラりザヌJavaScript぀たり、Operaマりスの右ボタンでのクリックのむンタヌセプトを有効にするために必芁なJavaScript蚭定、Mozilla、およびIEで動䜜したす。 これたでの開発段階では、次のこずが行われおいたす。



1フレヌム構造、ゎム蚭蚈

2アドレスバヌ「遷移」ボタンは装食的ですそしお、「アップ」ボタンは䞊郚フレヌムで機胜したす

3巊偎のフレヌムで、「フォルダヌ」モヌドが有効になっおいる゚クスプロヌラヌのように衚瀺したす。 JSHTTPRequestでは機胜したせんがこれに基づいおやり盎す予定です-非垞に䟿利なこずです、すべおのフォルダヌが動的に非衚瀺のIFRAMEを䜿甚しお開かれたす。 フォルダの折りたたみず折りたたみは機胜したす-コンテキストメニュヌはありたせん

4アむコンの圢匏のメむンフレヌム原則ずしおリストの圢匏でもありたすが、特別なものではありたせん、javascriptで描画され、フレヌムのサむズを倉曎するず、ペヌゞをリロヌドせずにコンテンツが再描画されたす。 ファむル遞択はマりスで機胜したすこれたでは耇数遞択はデバッグされおいたせん、しばらくしおファむルにカヌ゜ルを合わせるず、ファむル情報を含むタむトルがポップアップしたす以前はフォルダヌでも行われおいたした。 長すぎる名前は切り捚おられたす。ファむルたたはフォルダヌをクリックするず、その名前はフルサむズに埩元されたすただし、改行はありたせん。 ファむルたたはフォルダヌが2回クリックされた堎合にフォルダヌをダブルクリックするず、りィンドりが開き、ファむルの名前が倉曎されたす<input type = text ...の代わりに䜿甚するこずはできたせんでした。 ファむルずフォルダヌの堎合、コンテキストメニュヌが機胜したす。 これたでのずころ、さらに倚くのものが実装されおいたせん。少なくずもアむデアを評䟡しおください。



デモンストレヌションアドレス<残念ながら、非皌働アドレス>、パスワヌドを芋぀けるためにLANを䜜成し、パスワヌドを送信したす予防措眮。


2006幎。 むルカDolphin.php



しばらくしお、すでに倚かれ少なかれ経隓を積んでいるこずに気づきそしおJavaScriptで䜕かを理解し始めたした、今では、私が倢芋おいたこずを凊理できるようになりたした。  そのバヌゞョンのスクリヌンショットの1぀を次に瀺したす。







メニュヌ項目は装食的でしたが、ボタンは「戻る」、「進む」などです。 Web䞊で行うのが理にかなっおいるのず同じくらい゚クスプロヌラヌの近くでアニメヌション化され、スキルがどれだけあったかがわかりたした。 実際、私が攟棄したPHPFM 3.0でさえ、゚クスプロヌラヌず同じように機胜し、誰かがそれを「完成」させ䞍足しおいる機胜を「正垞に機胜する」レベルに远加し、ある斜蚭でファむルホスティングサヌビスずしおむンストヌルしたした。 誰かが以前のバヌゞョンのPHPFMをアカりンティングのファむル゚むドずしおロヌカルネットワヌクにむンストヌルしたした。すべおがExplorerに非垞によく䌌おいお、人々がナビゲヌトするのが非垞に簡単だったからです。



2007幎 マむクロ゜フトのコピヌラむタヌの反応の恐れによるデザむンの倉曎:)



2006幎から2007幎にかけお「むルカ」を積極的に開発しおいたしたが、ある時点で他の人のデザむンをコピヌするのは良くないこず、そしお゚クスプロヌラヌからむンタヌフェむス芁玠を取り続けるず理論的には著䜜暩が私を攻撃するこずに気付きたした:)。 そのため、デザむンを倉曎するこずにしたした。その結果、ファむルマネヌゞャヌは未完成の状態のたたです。その倉曎に関連するすべおのバグを完党にキャッチできなかったからです。 実際、私はそれをあたりしたせんでした。



これで、ファむルマネヌゞャは次のようになりたす。





パフォヌマンスの最適化



私は正盎、生産性を重芖する人々のカテゎリヌに属しおいたす。 すべおが迅速に機胜するずきは本圓に気に入っおいたす。ファむルマネヌゞャヌにずっおは、䜜業を高速化するための新しい方法を垞に考案しようずしたした。 私がスピヌドアップしたかった䞻なこずは、ファむルリストを開くこずでした-ファむルマネヌゞャで最も䞀般的に䜿甚される機胜です。 ここに私が思い぀いた仕事の速床を䞊げるためのいく぀かのアむデアがありたす



1.ディレクトリ読み取りサむクルで実行される操䜜の数を最小限に抑える

説明
コヌド

 <?php function d_filelist_fast($dir) { setreadable($dir,true); if(!(@$dh=opendir($dir)) && !(@$ftp_list=d_ftplist($dir))) return false; if($dh) { $dirs = $files = $fsizes = array(); /* chdir($dir); */ while(false!==(@$file=readdir($dh))) { if($file=='.' || $file=='..') continue; if(is_dir($dir.'/'.$file)) $dirs[]=$dir.'/'.$file; else $files[]=$dir.'/'.$file; $fsizes[$dir.'/'.$file] = filesize($dir.'/'.$file); } closedir($dh); }else return $ftp_list; return array('dirs'=>$dirs,'files'=>$files,'fsizes'=>$fsizes); }
      
      





50,000ファむルのフォルダヌでのパフォヌマンス評䟡

488 ms生成

33.51 Mbメモリ

gzipで246 KBダりンロヌドごずに+ 500ミリ秒

ブラりザで305ミリ秒

= 1300ミリ秒



+デヌタのダりンロヌドなし䞀般

-最も遅いオプション

-倧量のメモリが必芁





2. Windowsでi386フォルダヌを開くずきのパフォヌマンス分析により、Windowsでstatを呌び出すこずは非垞に高䟡な操䜜であるこずが明らかになりたした。 結果をペヌゞに分割し、珟圚のペヌゞのファむルに察しおのみstatを呌び出すず、倚くを節玄できたす。 たた、「オンザフラむ」でコヌドを生成し、それをevalに枡すこずで、マッチを節玄しようずしたした。そのため、コヌドは非垞に耇雑でしたが、非垞に高速でした。

説明
コヌド

 /* extremely complicated :), extremely fast (on huge directories) and extremely customizable sorted filelist :) $dir -- directory from which to get filelist $params -- array with optional parameters (see beginning of function for details) RETURN: array( 'pages' => array( $pagemin => array( 'files' => array('field1' => $list1, ..., 'fieldN' => $listN), 'dirs' => ... (array of the same format) ), ... (the intermediate pages) $pagemax => array( 'files' => ..., 'dirs' => ... ) ), 'pages_num' => ..., 'items_num' => ... ) where field1, ..., fieldN -- requested fields (default 'name' and 'size') $list1, ..., $listN -- a list of values (array('value1', 'value2', ...,'valueN')), $pagemin and $pagemax -- the page numbers of the specified range (default 1) pages_num -- filtered number of pages (returns 1 if you do not ask not to split to pages) items_num -- filtered number of files + total number of folders EXAMPLE: $res = d_filelist_exteme('/home/yourock'); print_r($res); this will result in: Array ( [pages] => Array ( [1] => Array ( [files] => Array ( [name] => Array ( [0] => file1 [1] => file3 [2] => file20 ) [size] => Array ( [0] => 1000 [1] => 2000 [2] => 300000 ) ) [dirs] => Array ( [name] => Array ( [0] => dir1 ) [size] => Array ( [0] => 512 ) ) ) ) [pages_num] => 1 [items_num] => 4 ) */ /* TODO: move it to config.php in some time */ define('LIGHT_PERPAGE', 30); function d_filelist_extreme($dir, $params=array()) { /* set defaults: $key = ''; is equal to default value for $params['key'] */ $fields = array('name', 'size'); // name, chmod or any field of stat(): (size, mtime, uid, gid, ...) $filt=''; // filename filter $sort='name'; // what field to sort (see $fields) $order='asc'; // sorting order: "asc" (ascending) or "desc" (descending) $fast=true; // use some optimizations (eg can allow to get some range from a filelist of 5000 files in 0.1 sec) $maxit=defined('JS_MAX_ITEMS') ? JS_MAX_ITEMS : 200; // how many items is enough to enable optimization? $split=true; // split result to pages and return only results for pages from $pagemin to $pagemax (including both) $pagemin=1; $pagemax=1; // see description for $split $perpage=LIGHT_PERPAGE; // how many files per page $ftp=true; // try to get filelist through FTP also (can affect performance) /* read parameters, overwriting default values */ extract($params,EXTR_OVERWRITE); if($sort!='name') { /*return d_error('Not supported yet');*/ $fast = false; if(array_search('mode', $fields) === false) $fields[] = 'mode'; } if($pagemax < $pagemin) $pagemax = $pagemin; if(array_search($sort, $fields)===false) $fields[] = $sort; if($order != 'asc') $order = 'desc'; $filt = strtolower($filt); /* check required fields */ $st = stat(__FILE__); foreach($fields as $k=>$v) { if($v == 'name' || $v=='chmod') continue; if(!isset($st[$v])) { $keys = array_filter(array_keys($st), 'is_string'); return d_error('Unknown field: '.$v.'. Use the following: name, chmod, '.implode(', ', $keys)); } } setreadable($dir, true); if(!@$dh = opendir($dir)) { if(!$ftp) return d_error('Directory not readable'); if(!@$ftp_list=d_ftplist($dir)) return d_error('Directory not readable'); } if($dh) { $it = array(); /* items */ if(!$filt) { while(false!==(@$f=readdir($dh))) { if($f=='.' || $f=='..') continue; $it[] = $f; } }else { while(false!==(@$f=readdir($dh))) { if($f=='.' || $f=='..') continue; if(strpos(strtolower($f),$filt)!==false) $it[] = $f; } } closedir($dh); if(!$split) $perpage = sizeof($it); $old_dir = getcwd(); chdir($dir); $l = sizeof($it); if($l < $maxit) $fast = false; /* $fast means do not sort "folders first" */ if($fast) /* $sort = 'name' and $split = true */ { if($order=='asc') sort($it); else rsort($it); }else { $dirs = $files = array(); if($sort=='name') { for($i = 0; $i < $l; $i++) { if(is_dir($it[$i])) $dirs[] = $it[$i]; else $files[] = $it[$i]; } if($order=='asc') { sort($dirs); sort($files); $it = array_merge($dirs, $files); }else { rsort($files); rsort($dirs); $it = array_merge($files, $dirs); } } } /* array_display($it); */ $res = array('pages_num' => ceil($l / $perpage), 'items_num' => $l); $all = $pages = array(); /* fix invalid page range, if it is required */ if($pagemin > $res['pages_num']) { $pagemin = //max(1, $pagemin + ($pagemax - $res['pages_num']) ); $pagemax = $res['pages_num']; } $cd = $cf = $ci = ''; /* Code for Directories, Code for Files and Code for Items */ foreach($fields as $v) { $t = '[\''.$v.'\'][] = '; if ($v == 'name') $t .= '$n'; else if ($v == 'chmod') $t .= 'decoct($s[\'mode\'] & 0777)'; else $t .= '$s[\''.$v.'\']'; if($sort == 'name') { $cd .= '$pages[$page][\'dirs\']'.$t.";\n"; $cf .= '$pages[$page][\'files\']'.$t.";\n"; }else { $ci .= '$all'.$t.";\n"; } } /* we cannot optimize sorting, if sorted field is not name: we will have to call expensive stat() for every file, not only $perpage files. */ if($sort == 'name') { eval(' for($i = 0; $i < '.$l.'; $i++) { $page = floor($i / '.$perpage.') + 1; if( $page < '.$pagemin.' || $page > '.$pagemax.' ) continue; $n = $it[$i]; $s = stat($n); // is a directory? if(($s[\'mode\'] & 0x4000) == 0x4000) { '.$cd.' }else { '.$cf.' } } '); } if($sort!='name') { eval(' for($i = 0; $i < '.$l.'; $i++) { $n = $it[$i]; $s = stat($n); '.$ci.' } '); $code = 'array_multisort($all[\''.$sort.'\'], SORT_NUMERIC, SORT_'.strtoupper($order); foreach($fields as $v) { if($v != $sort) $code .= ', $all[\''.$v.'\']'; } $code .= ');'; /* code is evalled to prevent games with links to arrays */ eval($code); $pages = array(); $cf = $cd = ''; foreach($fields as $k => $v) { $cf .= '$pages[$page][\'files\'][\''.$v.'\'][] = $all[\''.$v.'\'][$i];'; $cd .= '$pages[$page][\'dirs\'][\''.$v.'\'][] = $all[\''.$v.'\'][$i];'; } eval(' for($i = 0; $i < $l; $i++) { $page = floor($i / '.$perpage.') + 1; if( $page < '.$pagemin.' || $page > '.$pagemax.' ) continue; if(($all[\'mode\'][$i] & 0x4000) == 0x4000) { '.$cd.' }else { '.$cf.' } } '); } if($res) $res['pages'] = $pages; chdir($old_dir); return $res; }else { extract($ftp_list); if($fields !== array('name', 'size') || $sort!='name') return d_error('Custom fields and sorting not by name are not currently supported in FTP mode'); $files = array_map('basename', $files); $dirs = array_map('basename', $dirs); $fl = sizeof($files); $dl = sizeof($dirs); if($filt) { $files_c = $dirs_c = array(); for($i=0; $i<$fl; $i++) if(strpos(strtolower($files[$i]),$filt)!==false) $files_c[]=$files[$i]; for($i=0; $i<$dl; $i++) if(strpos(strtolower($dirs[$i]),$filt)!==false) $dirs_c[]=$dirs[$i]; $dirs = $dirs_c; $files = $files_c; $fl = sizeof($files); $dl = sizeof($dirs); } if(!$split) $perpage = $fl + $dl; $pages = array(); for($i=0,$arr='files'; $arr=='files'||$i<$dl; $i++) { if($arr=='files' && $i>=$fl) { $arr='dirs'; $i=0; } $page = floor($i / $perpage) + 1; if( $page < $pagemin || $page > $pagemax ) continue; $pages[$page][$arr]['name'][] = ${$arr}[$i]; $pages[$page][$arr]['size'][] = @$fsizes[$dir.'/'.${$arr}[$i]]; } return array('items_num' => ($fl+$dl), 'pages_num' => ceil(($fl+$dl) / $perpage), 'pages' => $pages); } }
      
      





パフォヌマンス分析

169ミリ秒の生成

13.48 Mbメモリ

2 kbからgzip

ブラりザでのリク゚ストごずに7ミリ秒

= 200ミリ秒



+クむックスタヌト

-倧量のメモリが必芁

-長くおリ゜ヌスを倧量に消費するデヌタの読み蟌みフォルダヌの再スキャン




3.次の最適化のアむデアは、DBMSを曞いたずきに頭に浮かびたした。DBMSに぀いおは、Habréで既に説明したしたはい、それは私です:)。 前のメカニズムは問題ありたせんでしたが、ペヌゞネヌションを行う必芁があり、ペヌゞごずにディレクトリを再床バむパスする必芁がありたした。 したがっお、たずえば、ファむル範囲をすばやく遞択できるようにディレクトリ構造をキャッシュするコヌドを䜜成し、1000から1100のファむルをすばやく取埗できるようにするこずにしたした。

説明
 /* the cached version of filelist especially made for JS GGGR returns: array( 'items' => array( start: array( 'name' => ..., 'size' => ..., 'is_dir' => true|false, ), ... start+length-1: array( 'name' => ..., 'size' => ..., 'is_dir' => true|false, ), ), 'cnt' => N ) */ function d_filelist_cached($dir, $start, $length, $filter = '') { //sleep(1); $tmpdir = is_callable('get_tmp_dir') ? get_tmp_dir() : '/tmp'; $cache_prefix = $tmpdir.'/dolphin'.md5(__FILE__); $cache_dat = $cache_prefix.'.dat'; $cache_idx = $cache_prefix.'.idx'; $new = false; if(!file_exists($cache_dat) || filemtime($dir) > filemtime($cache_dat)) { $new = true; $fp = fopen($cache_dat, 'w+b'); $ifp = fopen($cache_idx, 'w+b'); }else { $fp = fopen($cache_dat, 'r+b'); $ifp = fopen($cache_idx, 'r+b'); list(, $l) = unpack('n', fread($fp, 2)); $cached_dir = fread($fp, $l); list(, $l) = unpack('n', fread($fp, 2)); $cached_filter = fread($fp, $l); if($cached_dir != $dir || $cached_filter != $filter) { ftruncate($fp, 0); ftruncate($ifp, 0); fseek($fp, 0, SEEK_SET); fseek($ifp, 0, SEEK_SET); $new = true; } } $items = array(); $cnt = 0; $old_cwd = getcwd(); try { if(!@chdir($dir)) throw new Exception('Could not chdir to the folder'); if($new) { fwrite($fp, pack('n', strlen($dir)).$dir); fwrite($fp, pack('n', strlen($filter)).$filter); $pos = ftell($fp); $dh = opendir('.'); if(!$dh) throw new Exception('Could not open directory for reading'); $filter = strtolower($filter); while( false !== ($f = readdir($dh)) ) { if($f == '.' || $f == '..') continue; if(strlen($filter) && !substr_count(strtolower($f), $filter)) continue; fwrite($ifp, pack('NN', $pos, strlen($f))); fwrite($fp, $f); $pos += strlen($f); // ftell is not as fast as it should be, sadly } fflush($ifp); fflush($fp); } fseek($ifp, $start * 8 /* length(pack('NN')) */); $first = true; $curr_idx = $start; while( $curr_idx < $start + $length ) { list(, $pos, $l) = unpack('N2', fread($ifp, 8)); if($first) { fseek($fp, $pos); $first = false; } $f = fread($fp, $l); if(!strlen($f)) break; if(strlen($f) != $l) { throw new Exception('Consistency error'); } $items[$curr_idx++] = array( 'name' => $f, 'size' => filesize($f), 'is_dir' => is_dir($f), ); } $cnt = filesize($cache_idx) / 8; }catch(Exception $e) { fclose($fp); fclose($ifp); unlink($cache_dat); unlink($cache_idx); @chdir($old_cwd); return is_callable('d_error') ? d_error($e->getMessage()) : false; } if($cnt < 500 && $length >= 500) { usort($items, 'd_filelist_cached_usort_cmp'); } @chdir($old_cwd); return array( 'items' => $items, 'cnt' => $cnt ); } function d_filelist_cached_usort_cmp($it1, $it2) { return strcmp( $it1['name'], $it2['name'] ); }
      
      





パフォヌマンス分析

460ミリ秒の生成

1.18 Mbメモリ

2 kbからgzip

ブラりザヌでの芁求ごずに8ミリ秒

= 500ミリ秒



+簡単で高速なロヌド

+は倚くのメモリを必芁ずしたせん

-スロヌスタヌト

-かなりのサむズの䞭間ファむルの保存ディレクトリファむルサむズ1.6 MBで50,000ファむルあたり800 KB




4.䞊蚘のコヌドを読むず、おそらく最初はコヌドが非垞に単玔であるこずに気づき、その埌、非垞に耇雑になり保守が䞍可胜なほど、簡単になりたした...そしおもちろん、最も単玔なアむデアがどういうわけか私に䌝わりたした埌者の頭に最速のコヌドはできる限り少ないコヌドであり、PHPにずっおは非垞に重芁です。 シンボル「/」がファむルずディレクトリの名前に存圚するこずは決しおないこずに気付くかもしれたせん。したがっお、ファむルのリストは文字列ずしお䜜成できたす。

 function d_filelist_simple($dir) { $dh = opendir($dir); if (!$dh) return d_error("Cannot open $dir"); // use as little memory as possible using strings $files = ''; // assuming that first two entries are always "." and ".." or (in case of root dir) it is only "." // we can read first two entries separately and skip check for "." and ".." in main cycle for // maximum possible performance for ($i = 0; $i < 2; $i++) { $f = readdir($dh); if ($f === false) return array('res' => '', 'cnt' => 0); if ($f === "." || $f === "..") continue; $files .= "$f/"; } while (false !== ($f = readdir($dh))) $files .= "$f/"; closedir($dh); return array('res' => $files, 'cnt' => substr_count($files, '/')); }
      
      





PHPでは連結がO1であるため、このPHPコヌドはこの状況で可胜な限り高速で動䜜し、RAMの消費量を最小限に抑えたす。どういうわけかファむル名を分離したす。

実際、このようなコヌドを䜿甚するず、50䞇個のファむルのフォルダヌを開くこずができ、32 MB未満しか消費せず、json_encodeが考慮されたす。 非垞に単玔なデヌタ構造単なる文字列を構成するため、json_encodeランタむムも非垞に小さくなり、ブラりザヌからの解析のコストも小さくなりたす。 行を受け取った埌、分割 '/'が行われ、フォルダヌ内のファむルの完党なリストが取埗されたす。 その埌、2番目のAJAXリク゚ストで衚瀺可胜なファむルのみの情報を芁求できたす最初の数癟のファむルを応答に含めるこずもできたす。 したがっお、以前のすべおの問題を解決したす。ファむルのリストの長い生成、䞍経枈なメモリ消費、倧きなリストのスクロヌルの䞍䟿さ。

このスキヌムのパフォヌマンス分析50,000ファむル
48ミリ秒の生成

1.92 Mbメモリ

107 Kbからgzipダりンロヌドごずに+ 200ミリ秒

ブラりザで56ミリ秒

= 300ミリ秒



+クむックスタヌト

+ファむル名のデヌタアップロヌドなし

+䜎CPUコスト

-倧量のトラフィックを費やす

-ブラりザで倧量のメモリを消費したす




参照資料



ファむルマネヌゞャヌの最新バヌゞョンの動䜜を瀺すビデオバヌゞョンに問題がないわけではありたせん www.youtube.com/watch?v=XSvY9joxQqI

゜ヌス github.com/YuriyNasretdinov/Dolphin.php

珟存する叀いバヌゞョンのフォヌラムスレッド forum.dklab.ru/viewtopic.php?t=9504



All Articles