Как стать автором
Обновить

PHP для самых маленьких, или свой «Index of / » с преферансом и куртизанками

Предыстория

В процессе написания диплома возникла необходимость создать "он-лайн флешку" для хранения материалов.

Пользоваться облачными сервисами не хотелось, хотелось простоты использования, а именно: скопировал с компа на FTP, а затем с любого девайса выходом в интернет получаешь доступ ко всем файлам.


Способ 1. файл «.htaccess» с ключом «Оptions +Indexes»

Что меня не устроило:
1. Кодировка отображения страницы, читай, имён файлов, всегда CP1252
Icon  Name                    Last modified      Size  Description
[DIR] Parent Directory                             -   
[   ] Документ Mic..> 13-May-2014 00:21  314K  Документ Micro>
[   ] Компоновка..> 26-May-2014 23:51   20M  Фрагмент КОÐ>
[TXT] ЛТХ.txt              26-May-2014 23:49  728   
[   ] Раздел 00. ДÐ..> 13-May-2014 00:21   25K  Документ Micro>

Как c этим бороться я так и не понял, ключи AddDefaultCharset и CharsetSourceEnc не работают, а других вариантов управления кодировками я не нашёл.

2. Список файлов выгружается в узкую-узкую таблицу (таблица, она только визуально, а по тегам — это  моноширинным шрифтом)</code>

<code>3. Поле «Description», для меня в данном случае, не имеет смысла, т.к. его значение должно быть прописано вручную для каждого расширения. Файлы в папке могут быть самые разнообразные: документы, таблицы, рисунки, чертежи, —  для каждого типа их может быть больше десяти.</code>

<code>4. Иконки файлов. Отдельный пункт ненависти:</code>
<source lang="HTML">
<img src="/icons/back.gif" alt="[DIR]">
<img src="/icons/unknown.gif" alt="[   ]">
<img src="/icons/text.gif" alt="[TXT]">
</source>
<code>Они просто не отображаются. Почему? А потому что их там нет. Нет такой папки с такими файлами. Можно было бы создать самостоятельно, но зачем? Способов борьбы с ними я тоже не смог найти.</code>

<code>5. Невозможность применять стили. Да что там стили, вообще ничего применять нельзя.</code>
<code> </code>


<h5>Способ 2. index.php</h5>
<code>Самый очевидный: что-то не нравится? Возьми и создай своё с преферансом и куртизанками, чем я и занялся.</code>

<code>Оговорюсь сразу. PHP я видел два раза в жизни:</code>
<code>1. Когда делал именные приглашения на свадьбу (гость получал ссылку вида invite.mydomen.ru/?name=Сергей%20Анатольевич, и видел персональную страницу с приглашением, планом мероприятий и т.п.) </code>
<code>2. Когда помогал сестре в выполнении лабораторных работ по PHP в институте (дают список операторов, которые будут использованы в работе с объяснения и комментариями и простенькое задание)</code>
<code> </code>



<h5>И так, приступим</h5>
<code>По старой доброй традиции, всё сразу делается на продакшн, где и тестируется. Папка уже есть, создаём index.php</code>

<code>Первым делом нам надо получить выгрузить список файлов. Небольшие манипуляции с поисковым сервисом из шести букв, и начало положено.</code>
<source lang="php">
<?php
$dir = '../my_folder';	// определяем рабочую директорию
$f = scandir($dir);	// в массив заносим список файлов
foreach ($f as $file) {echo $file;}	// выводим список файлов (массив)
?>
</source>
<code>
Не с первого раз, но задача выполняется, а это главное. Осталось дело за малым, чуточку усложнить код, чтобы результатом его выполнения был тредуемый результат.
</code>

<code>Добавляем строки и ячейки таблицы, ссылки на файлы, новые поля (размер, расширение, дата изменения), а также заголовок таблицы.</code>

<source lang="php">
<?php
$dir = '../my_folder';
$f = scandir($dir);
echo '<html><head><title></title><style></style></head><body><table>';
echo '<tr> <th>Имя файла</th><th>Размер</th><th>Тип</th><th>Дата и время</th></tr>';
foreach ($f as $file) {
echo '<tr> <td><a href="'.$file.'">'.$file.'</a></td> <td>'.filesize($file).'</td> <td>'.end(explode('.',$file)).'</td> <td>'.date('d.m.Y H:i', filemtime($file)).'</td>';
}
echo '</table></body></html>';
?>
</source>
	
<code>В принципе, уже хорошо, и можно так оставить, но внутренний перфекционист душит хлеще любой жабы.</code>
	
<code>Добавляем стили, сокращаем размер (кБ, МБ, ГБ)... Ого, в выборку попали технические файлы *.php, .htaccess, папки — избавляемся. Попутно всплыло, что если имя файла содержит знак процента, то при попытке загрузить такой файл, сервер показывает ошибку 400. Ничего умнее не придумал, как заменять «%» на «%25».</code>

<source lang="php">
<?php
	$dir = '../my_folder';
	$f = scandir($dir);
	echo '<html><head><title></title><style></style></head><body><table>';
	echo '<tr> <th>Имя файла</th><th>Размер</th><th>Тип</th><th>Дата и время</th></tr>';
	
	foreach ($f as $file){
	    if(preg_match('/\.*/', $file)){
	        $stat = stat($file);
	        $size = filesize($file);
	
	        if ($size < 1024) {
	           $st = $size.' B' ;
	
	        } elseif ($size<1048576) {
	           $st = round(($size/1024),2).' KB' ;
	
	        } elseif ($size<1073741824) {
	           $st =  round(($size/1048576),2).' MB';
	
	        } else {
	           $st =  round(($size/1073741824),2).' G';
	}
	
	        // здесь условие
	        if (basename($file) == '.htaccess' || basename($file) == '.' || basename($file) == '..'|| strtoupper(end(explode('.', $file))) == 'PHP') continue;
	        echo '<tr><td><a href="'.str_replace('%','%25',$file).'">'.$file.'</a></td><td align=right>'.$st.'</td><td>'.strtoupper(end(explode('.', $file))).'</td><td>'.date('d.m.Y H:i', filemtime($file)).'</td></tr>
	';
	    }
	}
	echo '</table></body></html>';
	?>
</source>

<code>Почти хорошо. Добавляем стили, заголовок и фавикон. До сих пор имя папки, для которой мы делаем индексирование статично, и даже если перенести файл в соседнюю папку, отображаться будет текущая. Исправляем и это.</code>
	
<source lang="php">
	<?php
	$dr = end(explode('/', getcwd()));
	$dir = '../'.$dr;
	$f = scandir($dir);
	
	echo '<html>
	<head>
	<link rel="icon" type="image/png" href="data:image/gif;base64,R0lGODlhEAAQAKEBADmQzv///////////yH5BAEKAAIALAAAAAAQABAAAAIrlI+JoM3y2gG0yhSvybp7V4ViGJQlYKJoQLGu+p7wHLP06r53rY6+9TEUAAA7">
	<title>Index of /'.$dr.'</title>
	<style>
	body {background: #fff url(http://mai.megapolis-avto.com/background.gif) repeat-x;}
	fff{font-size:12pt;}
	body  {font-family:  Times New Roman; }
	table {border-collapse:collapse;}
	th {padding-bottom:15px; text-align: left;}
	td {empty-cells:show; margin:0px; border-bottom: 0px solid #efefef; padding: 0 10 ;}
	tr:hover td {background:#daeaf6;}
	td a, a:active {color: #3990ce; text-decoration: none;}
	td a:hover {color:red;}
	td a:visited {color: #5215a7; text-decoration: none;}
	</style>
	</head>
	<body>
	<h1>Index of /'.$dr.'</h1>
	<table>';
	echo '<tr> <th>Имя файла</th><th>Размер</th><th>Тип</th><th>Дата и время</th></tr>';
	
	foreach ($f as $file){
	    if(preg_match('/\.*/', $file)){
	        $stat = stat($file);
	        $size = filesize($file);
	
	        if ($size < 1024) {
	           $st = $size.' B' ;
	
	        } elseif ($size<1048576) {
	           $st = round(($size/1024),2).' KB' ;
	
	        } elseif ($size<1073741824) {
	           $st =  round(($size/1048576),2).' MB';
	
	        } else {
	           $st =  round(($size/1073741824),2).' G';
	}
	
	        // здесь условие
	        if (basename($file) == '.htaccess' || basename($file) == '.' || basename($file) == '..'|| strtoupper(end(explode('.', $file))) == 'PHP') continue;
	        echo '<tr><td><a href="'.str_replace('%','%25',$file).'">'.$file.'</a></td><td align=right>'.$st.'</td><td>'.strtoupper(end(explode('.', $file))).'</td><td>'.date('d.m.Y H:i', filemtime($file)).'</td></tr>
	';
	    }
	}
	echo '</table></body></html>';
	?>
</source>

<code>Есть один большой минус, который способен перечеркнуть все плюсы. Это отсутствие сортировки. Самое распространённое решение — это воспользоваться JS, но это не наш метод. Будем реализовывать сортировку через переменную $_GET</code>

<source lang="php">
...

$sorted =$_GET[sorted]; 
...
<thead><tr>
<th><a href="?sorted=name" title="Сортировать по имени">Имя файла</a></th>
<th><a href="?sorted=size" title="Сортировать по размеру">Размер</a></th>
<th><a href="?sorted=type" title="Сортировать по типу">Тип</a></th>
<th><a href="?sorted=time" title="Сортировать по дате">Дата и время</a></th>
</tr></thead>
...
$files = array(); 

if ($sorted =='time') {
foreach ($f as $file) $files[$file] = filemtime("$file");

} elseif ($sorted =='type') {
foreach ($f as $file) $files[$file] = strtoupper(end(explode('.', $file)));

} elseif ($sorted =='size') {
foreach ($f as $file) $files[$file] = filesize($file);

} else {
foreach ($f as $file) $files[$file] = ($file);
}

asort($files); 
$files = array_keys($files); 
	foreach ($files as $file){
    if(preg_match('/\.*/', $file)){
        $stat = stat($file);
        $size = filesize($file);
	        if ($size < 1024) {
           $st = $size.' B' ;

        } elseif ($size<1048576) {
           $st = round(($size/1024),2).' KB' ;

        } elseif ($size<1073741824) {
           $st = round(($size/1048576),2).' MB';

        } else {
           $st = round(($size/1073741824),2).' G';
}
        // здесь условие
       if (basename($file) == '.htaccess' || basename($file) == '.' || basename($file) == '..'|| strtoupper(end(explode('.', $file))) == 'PHP') continue;
        echo '<tr><td><a href="'.str_replace('%','%25',$file).'">'.$file.'</a></td><td align=right>'.$st.'</td><td>'.strtoupper(end(explode('.', $file))).'</td><td>'.date('d.m.Y H:i', filemtime($file)).'</td></tr>
';
   }
</source>

Ах-да, чуть не забыл экранирование символов в запросе:
	
<source lang="php">
$sorted=htmlspecialchars($_GET[sorted]); 
</source>

В конечном счётё файл выглядит так:

<source lang="php">
<?php
	
	$dr = end(explode('/', getcwd()));
	$dir = '../'.$dr;
	$f = scandir($dir);
	
	$sorted =htmlspecialchars($_GET[sorted]); 
	
	echo '<html>
	<head>
	<link rel="icon" type="image/png" href="data:image/gif;base64,R0lGODlhEAAQAKEBADmQzv///////////yH5BAEKAAIALAAAAAAQABAAAAIrlI+JoM3y2gG0yhSvybp7V4ViGJQlYKJoQLGu+p7wHLP06r53rY6+9TEUAAA7">
	<title>Index of /'.$dr.'</title>
	
	<style>
	body {background: #fff url(http://mai.megapolis-avto.com/background.gif) repeat-x;}
	fff{font-size:12pt;}
	body  {font-family:  Times New Roman; }
	table {border-collapse:collapse;}
	th {padding-bottom:15px; text-align: left;}
	td {empty-cells:show; margin:0px; border-bottom: 0px solid #efefef; padding: 0 10 ;}
	tr:hover td {background:#daeaf6;}
	th a  {color: #3990ce;  text-decoration: none; border-bottom: 1px solid #d6e4f5;}
	th a:active {color: black; text-decoration: none;}
	th a:hover {color:red;}
	td a, a:active {color: #3990ce; text-decoration: none;}
	td a:hover {color:red;}
	td a:visited {color: #5215a7; text-decoration: none;}
	</style>
	</head>
	<body>
	<h1>Index of /'.$dr.'</h1>
	<table>
	<thead><tr>
	<th><a href="?sorted=name" title="Сортировать по имени">Имя файла</a></th>
	<th><a href="?sorted=size" title="Сортировать по размеру">Размер</a></th>
	<th><a href="?sorted=type" title="Сортировать по типу">Тип</a></th>
	<th><a href="?sorted=time" title="Сортировать по дате">Дата и время</a></th>
	</tr></thead>
	 <tbody>
	'; 
	
	$files = array(); 
	
	if ($sorted =='time') {
	foreach ($f as $file) $files[$file] = filemtime("$file");
	
	} elseif ($sorted =='type') {
	foreach ($f as $file) $files[$file] = strtoupper(end(explode('.', $file)));
	
	} elseif ($sorted =='size') {
	foreach ($f as $file) $files[$file] = filesize($file);
	
	} else {
	foreach ($f as $file) $files[$file] = ($file);
	}
	
	asort($files); 
	$files = array_keys($files); 
	
	foreach ($files as $file){
	    if(preg_match('/\.*/', $file)){
	        $stat = stat($file);
	        $size = filesize($file);
	
	        if ($size < 1024) {
	           $st = $size.' B' ;
	
	        } elseif ($size<1048576) {
	           $st = round(($size/1024),2).' KB' ;
	
	        } elseif ($size<1073741824) {
	           $st =  round(($size/1048576),2).' MB';
	
	        } else {
	           $st =  round(($size/1073741824),2).' G';
	}
	
	        // здесь условие
	        if (basename($file) == '.htaccess' || basename($file) == '.' || basename($file) == '..'|| strtoupper(end(explode('.', $file))) == 'PHP') continue;
	        echo '<tr><td><a href="'.str_replace('%','%25',$file).'">'.$file.'</a></td><td align=right>'.$st.'</td><td>'.strtoupper(end(explode('.', $file))).'</td><td>'.date('d.m.Y H:i', filemtime($file)).'</td></tr>
	';
	    }
	}
	
	echo '
	</tbody>
	</table>
	</body>
	</html>
	';
	
	?>
</source>

<h5>Выводы</h5>
<code>И так, мы получаем:</code>
<ul>
	<li>файл, который можно применить в любой папке, просто поместив его в неё</li>
	<li>относительно, гибкая настройка и доработка</li>
	<li>предмет гордости</li>
	<li>бесценный опыт</li>
	<li>данный пост и возможность получить полезные советы в комментариях к посту.</li>
</ul>
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.