Архив метки: php

Corban, dear! — отладочная библиотека для PHP

Когда я в 2000-ом году пришел в Softerra, там для PHP во всю использовали небольшую, порядка 200 строк, самописную библиотеку для дебага «Corban, dear!». Первоначально написал её Боба, дав название по мотивам «Пятого элемента». Но так уж получилось что потом ей занимался я: под впечатлением от ColdFusion я сделал буферизированный вывод после завершения работы скрипта, добавил поддержку объектов, вывод методов класса, вывод в файл, написал документацию. Затем я ушел из Softerra, прошло пару лет и вместе с Бобой её основательно переписали. И мы до сих пор её используем, так как это намного лучше чем var_dump() или print_r().

Страница библиотеки на Google Project Hosting и на GitHub.

Ютюбоподобный хеш

Году в 2006 мы разрабатывали свой клон Ютюба. В этом проекте многие вещи пришлось разрабатывать с нуля. Например, мне очень хотелось использовать в проекте хеши подобные тем, что использует Ютюб. С ходу решения не нашлось и пришлось поразмышлять:

  1. Хеш Ютюба содержит 11 символов.
  2. Алфавит хеша состоит из 64 символов (по 26 заглавных и строчных букв латинского алфавита, 10 цифр, дефис и символ подчеркивания).
  3. На кодирование всех символов этого алфавита нужно 6 бит (2^6 = 64).
  4. Хеш Ютюба содержит 11 символов, т.е. 66 бит.
  5. Можно предположить что берется какой-то хеш в 64 бита, например половина MD5, дополняется до 66 и дробится на куски по 6 бит.
  6. Каждый кусок — это символ нашего алфавита.

Тогда у меня получился такой код:

function get_ylhash($data=null, $long=false)
{
	if (is_null($data))
	{
		if ( substr(PHP_VERSION, 0, 1) == '5')
		{	// PHP5
			$data = md5(uniqid(rand(), true), true);
		}
		else
		{	// < PHP5
			$data = md5(uniqid(rand(), true));
			$data = pack('H*', $data);
		}
	}

	if (!$long)
	{
		$data = substr($data, 0, 8);
	}

	$alphabet = '0123456789_abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ';
	$result = '';
	$m = $a = 0;
	for ($i=0, $len=strlen($data); $i<$len; $i++)
	{
		$c = ord($data{$i});
		$result .= $alphabet{($c << $m | $a) & 63};
		$a = $c >> (6-$m);
		$m += 2;
		if ( ($m==6) || ($i==$len-1) )
		{
			$result .= $alphabet{$a};
			$m = $a = 0;
		}
	}

	return $result;
}

Шли годы, я использовал эти ютюбоподобные хеши в дальнешйих проектах, пока до меня наконец дошло: преобразование бинароной последовательности в строку состоящую из символов алфавита с 64 знаками называется Base64. Немного погуглив я нашел rfc3548.txt, в разделе 4 которого описан стандарт Base64-кодирования для использования в URL и именах файлов.

В итоге получилась такая функция:

function get_ylhash($data=null, $long=false)
{
	$trans = array
	(
		'+' => '-',
		'/' => '_',
		'=' => '',
	);

	if (is_null($data))
	{
		$data = crypt( mt_rand().uniqid(), mt_rand().uniqid() );
	}

	$data = md5($data, true);

	if(!$long)
	{
		$data = substr($data, 0, 8);
	}

	$data = strtr(base64_encode($data), $trans);

	return $data;
}

Исходный код на GitHub.

Правильно закрываем сайт на техобслуживание

Был немного удивлен тем, как на текущей работе закрывают сайт на техобслуживание: перенаправляют все запросы на closed.php. Это не совсем удобно для посетителей, т.к. если в момент начала работ кто-то был на сайте, то в итоге окажется на непонятной странице. И очень не удобно для поисковиков, т.к. они получат какой-то мусор.

Правильным решением будет на время проведения технических работ на все запросы отдавать содержимое специальной страницы, вместе с 503 кодом состояния HTTP.

Для этого файл .htaccess должен выглядеть следующим образом:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$
RewriteCond $1 !^(closed\.php)
RewriteRule ^(.*)$ /closed.php [L]

А файл closed.php должен быть таким:

<?php
$online = '22.01.2014 14:40 +0400';
$online = strtotime($online);
header('Content-Type: text/html; charset=utf-8');
header('HTTP/1.1 503 Service Temporarily Unavailable');
header('Status: 503 Service Temporarily Unavailable');
header('Retry-After: '.gmdate(DATE_RFC822, $online));
?>
<html>
<head>
	<meta charset="utf-8" />
	<title>example.com: ведутся технические работы</title>
</head>
<body>
	<div style="text-align: center; width: 300px; height: 200px; position: absolute; top: 50%; left: 50%; margin-top: -100px; margin-left: -150px;">
		<h2>На сайте ведутся технические работы. Приблизительное время включения <?php echo date('H:i d.m.Y', $online); ?>.</h2>
	</div>
</body>
</html>

Исходный код на GitHub.