ОсновноеRadiotalkПользовательское
Программирование
6   •   Посмотреть все темы

PHP - Полезные советы, приёмы, функции

 

20089
Dimitry @Dimitry
Как лучше всего сохранять IP адреса для статистики.

Внимание! При сохраниении в базу данных, скрипт работает неверно из-за символа \0.

Например для написания системы счётчиков, обсчёта статистики посещений, требуется запись большого количества IP адресов и приходится часто сравнивать их, что приводит к высоким нагрузкам. Например мы сохраняем разные IP чтобы узнать сколько уникальных посетителей у нас было!

Далее описанный мой способ сохранения и проверки IP адресов улучшает производительность в 4 раза. (посравнению с обычным)

1. Способ сохранения
- в Mysql используем поле text
- в файлах, каждому аккаунту свой фаил с IP например в папке ips: ips/user1.dat
- при использовании памяти, необходимо выделить достаточно

2. Метод кодирования и оптимизации
Каждый IP выглядит примерно так: 123.123.123.123
получаем 15 символов + один символ для разделения IP-адресов = 16
Столько требуется для записи одного IP, а для 1000 выходит уже 16кб информации!
Уменьшаем в 4 раза следующим способом:
$ip=$_SERVER[REMOTE_ADDR]; $a=explode(".",$ip);
$ip=chr($a[0]).chr($a[1]).chr($a[2]).chr($a[3]);

Теперь наш IP закодирован и составляет всего 4 символа.
Добавление в фаил с IP адресами происходит без разделителя, он нам не нужен.

3. Как проверить присутствие такого IP в переменной (из файла или Mysql) и добавить новый.
Мы получаем переменную с нашими закодированными IP адресами например из файла так:
$ips=file_get_contents("ips/user1.dat");

Теперь закодируем наш IP для проверки его в файле:
$ip=$_SERVER[REMOTE_ADDR]; $a=explode(".",$ip);
$ip=chr($a[0]).chr($a[1]).chr($a[2]).chr($a[3]);

Проверим наличие $ip в переменной $ips перебирая их через каждые 4 символа:
$found=0;
for($i=0;$i<strlen($ips);$i+=4) if($ips[$i]==$ip[0]) if($ip==substr($ips,$i,4)) {$found=1;break;}

if($ips[$i]==$ip[0]) - используется для оптимизации процесса поиска
Теперь если IP ненайден то добавим его:
предполагается что у вас php4 и функция file_put_contents не существует, тогда воспользуемся стандартной процедурой добавления записи в фаил...
$f=fopen("ips/user1.dat","a");
fwrite($f,$ip);
fclose($f);

Для работы с MYSQL и памятью читайте на php.net
Ну вот и всё, считаю что это самый оптимальный и продуктивный способ для создания подобных систем.

4. Вероятно нам нужно получить все IP адреса и перекодировать их сново в нормальный вид
// $ips - переменная с IP адресами
//создадим массив для раскодированных IP адресов
$aips=array();
for($i=0;$i<strlen($ips);$i+=4) $aips[]=ord($ips[$i]).'.'.ord($ips[$i+1]).'.'. ord($ips[$i+2]).'.'. ord($ips[$i+3]);
//выведем полученные адреса
for($i=0;$i<count($aips);$i++) echo $aips[$i]."<br>";

5. Весь код для работы на файлах
//decode IP
$ip=$_SERVER[REMOTE_ADDR]; $a=explode(".",$ip);
$ip=chr($a[0]).chr($a[1]).chr($a[2]).chr($a[3]);

//read IPs
$ips=file_get_contents("ips/user1.dat");

//search IP
$found=0;
for($i=0;$i<strlen($ips);$i+=4) if($ips[$i]==$ip[0]) if($ip==substr($ips,$i,4)) {$found=1;break;}

//save IP
if($found==0) {
$ips.=$ip;
$f=fopen("ips/user1.dat","a");
fwrite($f,$ip);
fclose($f);
}

//encode all IPs in Array
$aips=array();
for($i=0;$i<strlen($ips);$i+=4) $aips[]=ord($ips[$i]).'.'.ord($ips[$i+1]).'.'. ord($ips[$i+2]).'.'. ord($ips[$i+3]);

//output to see in HTML
for($i=0;$i<count($aips);$i++) echo $aips[$i]."<br>";

Вероятно это никому не пригодится, но может всё таки... или же я сам посмотрю когда забуду )


2007 copyright by demon

20089
Dimitry @Dimitry
Идеальная структура проекта - карказ сайта

Ну с чего начинается любой сайт, конечно же с index.php.
Что же в нём находится? Дизайн? Нет!
Из своего опыта я убедился в том что самым удобным образом, index.php выглядит так!

<?php
define("INDEX",1);

//include functions and connect to mysql
include("config.php");

//cache and design
register_shutdown_function("output");

function output() {
global $design,$title,$menu,$time_start,$to;
chdir(__DIR__);
$index=ob_get_contents();
ob_end_clean();
$design=file_get_contents("design.html");
$time_end=round((getmicrotime()-$time_start)*1000)/1000;
echo str_replace(array("%title%","%menu%","%index%","%time%"),array($title,$menu,$index,$time_end),$design);
}

//include menu
ob_start();
include("menu.php");
$menu=ob_get_contents();
ob_clean();

//include content
$to=$_GET[to];
if(preg_match("/^[a-z-]+$/",$to) && $to!="index" && is_file("$to.php")) include("$to.php");
else include("home.php");

?>

Думаю даже некоторые профи не знают этого метода и непонимают всех его плюсов.

Почему этот метод?

- вы можете использовать всего один шаблон с дизайном для всего сайта, нпример design.html
- вы можете использовать setcookie() и header() в любом месте, в любое время, в любых скриптах
- вы можете завершить выполнение модуля через die(), в любом месте в любое время и при этом дизайн будет полностью загружен
- вы определяете время выполнения скрипта в любых модулях, причём ничего не прописывая в них
- вы имеете высокую безопастность и гарантию того что скрипты запускаются именно через index.php, т.е. проходят всё что вы в нём укажите
- а главное - удобство, динамичность, мало PHP кода

Как работает этот метод?

1. Сначало индекс сообщает о том что он индекс: define("INDEX",1);
и для загрузки всех модулей сначало загружается сам индекс,
для этого каждый модуль должен начинаться с
<?
if(!defined("INDEX")) die('ошибка загрузки сайта');
$title="заголовок модуля";

2. Модули загружаются в основной дизайн и вызываются ссылками
index.php?to=module
В нашем методе мы регистрируем функцию output(), которая при завершении или ошибке скрипта загружает дизайн, который до этого просто кешируется в памяти.
register_shutdown_function("output");

Например так мы загружаем меню в переменную $menu

//include menu
ob_start();
include("menu.php");
$menu=ob_get_contents();
ob_clean();

А в функции output() читаем содержимое модуля в переменную $index, определяем время выполнения скрипта,читаем дизайн из файла и вносим в него меню, модуль, время , заголовок

$design=file_get_contents("design.html");
$time_end=round((getmicrotime()-$time_start)*1000)/1000;
echo str_replace(array("%title%","%menu%","%index%","%time%"),array($title,$menu,$index,$time_end),$design);

3. Как же выглядит шаблон дизайна design.html
<html>
<head>
<tilte>%title%</title>
</head>
<boby>
LOGO
<table width=800 height=100%>
<tr>
<td width=200>%menu%</td>
<td>%index%</td>
</tr>
</table>
<center>Загружено за %time% сек</center>
</body>
</html>

Что находится в config.php

В жтом файле находятся все настройки, переменные, подключение в базе mysql, а также основные функции.
Например у меня там функция регистрирующая время в милисекундах, для определения времени выполнения скрипта.

<?
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$time_start = getmicrotime();
?>

2008 copyright by demon

20089
Dimitry @Dimitry
Функция чтения строк файла с конца rfile()

Существует функция file(), которая читает весь фаил в массив строк.
Но возникает проблема при больших файлах, особенно если требуется прочитать только последние 10 строк.
Вот я и написал функцию rfile() которая читает несколько последних строк с конца файла и сохраняет их в массив, работает быстро!

function rfile($file,$num=10) {
$buf=1024;
if(!is_file($file)) return;
$f=fopen($file, 'r');
$pos=filesize($file)-1;
$c=0;$read="";
while($pos>0) {
$pos-=$buf;
if($pos<0) {$buf+=$pos;$pos=0;}
fseek($f,$pos);
$tmp=fread($f,$buf);
$c+=substr_count($tmp,"\n");
$read=$tmp.$read;
if($c>$num) break;
}
fclose($f);
$a=explode("\n",$read);$c=count($a); $r=array();
if(!$a[$c-1]) {unset($a[$c-1]);$c--;}
$start=$c-$num; if($start<0) $start=0;
for($i=$start;$i<$c;$i++) $r[]=$a[$i]."\n";
return $r;
}

2009 copyright by demon

20089
Dimitry @Dimitry
Функция удалённого получения содержимого страницы или файла через URL
(функция почти аналогична file_get_contents(), но работать будет даже с выключенной в PHP поддержкой удалённых подключений)

Примеры использования методом GET (через URL):

$content=req("http://domain.ru"); //скачаем содержимое главной страницы
$content=req("http://domain.ru/image.gif"); //скачаем картинку
$content=req("http://domain.ru/archiv.rar"); //скачаем архив
$content=req("http://domain.ru/info.php"); //скачаем HTML отдаваемый php файлом
$content=req("http://domain.ru/info.php?user=admin"); //скачаем HTML отдаваемый php файлом c GET параметрами user=admin
$content=req("http://domain.ru:81/index.php"); //скачиваем содержимое с указанием своего порта
$content=req("https://domain.ru/index.php"); //скачиваем содержимое через SSL (https) подключение
$content=req("https://domain.ru:443/index.php"); //скачиваем содержимое через SSL (https) подключение с указанием своего порта

Также можно делать запросы методом POST (как-бы через форму), достаточно указать второй параметр:

$content=req("http://domain.ru/login.php","user=admin&password=123");
(скачиваем содержимое передав параметры авторизации скрипту login.php методом POST)
$content=req("http://domain.ru/index.php?to=login","user=admin&password=123");
(совмесное использование методов GET (to=login) и POST (user=admin&password=123) )
$content=req("http://domain.ru/index.php?to=login",array("user"=>"admin","password"=>"123"));
(но лучше всего передавать параметры в POST запрос через массив)

Вы можете передать ещё один параметр $full=1, в этом случае будет выводиться не только содержимое, а заголовок запроса, заголовок ответа и содержимое. (разделяются 2мя переходами строки \r\n\r\n):
$content=req("http://domain.ru/index.php?to=login","user=admin&password=123",1);

Следующим параметром вы можете настроить таймаут для подключения/операции чтения: $timeout=3
а также принудительное завершение всего скрипта с выводом ошибки: $die=1


//$content=req("https://user:pass@domain:443/file.php?get=variable","post=variable");
function req($url,$post="",$full=0,$timeout=3,$die=1) {
$err=array("Неправильный URL запроса!","Невозможно подключиться!","Невозможно получить данные!");
$url=@parse_url($url);
if(!ereg("^(http|https)://[a-z0-9.:-]+/","$url[scheme]://$url[host]/")) {if($die) die("$err[0]"); return;}
if(!$url[path]) $url[path]="/"; if($url[scheme]=="https") $type="ssl://"; else $type="";
if(!$url[port]) {if($url[scheme]=="https") $url[port]=443; else $url[port]=80;}
$method="GET"; if($url[query]) $url[query]="?$url[query]";
$contents=""; if($url[user] && $url[pass]) $contents.="Authorization: Basic ".base64_encode("$url[user]:$url[pass]")."\r\n";
if($post) {$method="POST"; if(is_array($post)) $post=http_build_query($post); else $post=str_replace(array("%3D","%26"),array("=","&"),urlencode($post)); $contents.="Content-Type: application/x-www-form-urlencoded\r\nContent-Length: ".strlen($post)."\r\n";}
$send="$method $url[path]$url[query] HTTP/1.0\r\nHost: $url[host]\r\nUser-Agent: Mozilla\r\n$contents\r\n$post";
//$socket_context = stream_context_create(array('socket' => array('bindto' => '123.123.123.123:0')));
if(!$f = @stream_socket_client("$type$url[host]:$url[port]", $errno,$errstr, $timeout, STREAM_CLIENT_CONNECT)) {if($die) die("$err[1]"); return;}
else {
fwrite($f,$send); stream_set_timeout($f,$timeout); $info=stream_get_meta_data($f);
if($type) stream_set_blocking($f, FALSE); $time_start=time();
$r=""; while(!feof($f) && !$info['timed_out']) {$read=fread($f,8192); $r.=$read; $info=stream_get_meta_data($f); if($type) {if(!$read) {if($usleep<1000000) $usleep+=10000; usleep($usleep);} if(time()-$time_start>$timeout) $info['timed_out']=1;}}
fclose($f);
if($info['timed_out']) { if($die) die("$err[2]"); return;}
}
if($full) return "$send$r";
$pos=strpos($r,"\r\n\r\n");if($pos) $r=substr($r,$pos+4);
return $r;
}

2009 copyright by demon

20089
Dimitry @Dimitry
Скриптовая эмуляция изменения глобальных настроек в php.ini
- magic_quotes_gpc
- magic_quotes_runtime
- register_globals
- register_long_arrays

Если вам попался хостинг на котором нет возможности прописать эти глобальные настройки в .htaccess или php.ini, то вы можете воспользоваться этим уникальным скриптом.
Просто вставьте этот скрипт в конфиг фаил вашего сайта или в самый верх каждой страницы/пхп-файла.
Этот скрипт изменит данные настройки php и не оставит никаких следов вмешательств после себя.
Данный скрипт поможет вам запускать скрипты созданные на php3, php4 и php5.
Пропистаь скрипт в пхп-файле можно такой строчкой: include_once("ini-set.php");

А вот и сам скрипт: ini-set.php
<?php

//PHP HARD INI-SETTINGS EMULATION by Dimitry Bansikov
$magic_quotes_gpc=0; //used in php < 5.2.3
set_magic_quotes_runtime(0); //don't need to change normally
$register_globals=1; //used in php < 5.2.3
$register_long_arrays=0; //used in php < 4.0.2

//magic_quotes_gpc ON
if ($magic_quotes_gpc && !get_magic_quotes_gpc()) {
foreach ($_GET as $k => $v) $_GET[$k]=addslashes($v);
foreach ($_POST as $k => $v) $_POST[$k]=addslashes($v);
foreach ($_COOKIE as $k => $v) $_COOKIE[$k]=addslashes($v);
ini_set('magic_quotes_gpc', true);
define("RENEW_MQ",1);
}
//magic_quotes_gpc OFF
if (!$magic_quotes_gpc && get_magic_quotes_gpc()) {
foreach ($_GET as $k => $v) $_GET[$k]=stripslashes($v);
foreach ($_POST as $k => $v) $_POST[$k]=stripslashes($v);
foreach ($_COOKIE as $k => $v) $_COOKIE[$k]=stripslashes($v);
ini_set('magic_quotes_gpc', false);
define("RENEW_MQ",1);
}
//update $_REQUEST for magic_quotes_gpc
if(defined("RENEW_MQ")) {
foreach ($_GET as $k => $v) $_REQUEST[$k]=$v;
foreach ($_POST as $k => $v) $_REQUEST[$k]=$v;
foreach ($_COOKIE as $k => $v) $_REQUEST[$k]=$v;
}

//register_globals ON
if ($register_globals && (!ini_get('register_globals') || defined("RENEW_MQ"))) {
if(defined("RENEW_MQ")) foreach ($_REQUEST as $k => $v) unset($GLOBALS[strtolower($k)]);
$superglobals = array($_SERVER, $_ENV, $_FILES, $_COOKIE, $_POST, $_GET);
if (isset($_SESSION)) array_unshift($superglobals, $_SESSION);
foreach ($superglobals as $superglobal) extract($superglobal, EXTR_SKIP);
ini_set('register_globals', true);
}
//register_globals OFF
if (!$register_globals && ini_get('register_globals')) {
$superglobals = array($_SERVER, $_ENV,$_FILES, $_COOKIE, $_POST, $_GET);
if (isset($_SESSION)) array_unshift($superglobals, $_SESSION);
foreach ($superglobals as $superglobal) {
foreach ($superglobal as $k => $v) unset($GLOBALS[$k]);
}
ini_set('register_globals', false);
}

//register_long_arrays ON
if ($register_long_arrays && (!ini_get('register_long_arrays') || defined("RENEW_MQ"))) {
$HTTP_SERVER_VARS=$_SERVER; $HTTP_ENV_VARS=$_ENV;
$HTTP_POST_FILES=$_FILES; $HTTP_COOKIE_VARS=$_COOKIE;
$HTTP_POST_VARS=$_POST; $HTTP_GET_VARS=$_GET;
if(isset($_SESSION)) $HTTP_SESSION_VARS=$_SESSION;
ini_set('register_long_arrays', true);
}
//register_long_arrays OFF
if (!$register_long_arrays && ini_get('register_long_arrays')) {
unset($HTTP_SERVER_VARS, $HTTP_ENV_VARS, $HTTP_POST_FILES, $HTTP_COOKIE_VARS, $HTTP_POST_VARS, $HTTP_GET_VARS,$HTTP_SESSION_VARS);
ini_set('register_long_arrays', false);
}

//unset used variables
unset($magic_quotes_gpc,$register_globals,$register_long_arrays,$superglobals,$superglobal,$k,$v);

//to check this script uncomment
//echo "<pre>";print_r($GLOBALS);
?>

2009 copyright by demon

20089
Dimitry @Dimitry
Функция для работы с базой данных для удобства и исключения инъекций

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

Функция в процессе тестирования!

Описание:
$r=sql($table,$type,$fields,$where="",$limit="");
- данные передаваемые в $where требую предварительную фильтрацию на уязвимости
- $fields может быть как массивом, так и строкой, если строка - то требуется проверка на уязвимости
В получаемом результате:
$r[num] - кол-во полученных строк для select или ID добавленной строки для insert или кол-во затронутых строк для update/delete
$r[res] - результат запроса select для последующего чтения строк
$r[time] - время выполнения запроса

Пример подключения к базе:

$link = mysql_connect('localhost', 'MyLoginInMysql', 'MyPassword') or die('Ошибка соединения: ' . mysql_error());

Примеры запросов через фунцию:

$r=sql("db.table","select",$fields,"id=1","0,100");
$r=sql("db.table","insert",$fields);
$r=sql("db.table","update",$fields,"id=1");
$r=sql("db.table","delete","","id=1");

Подробные примеры:
$r=sql("db.table","select","*","id=1","0,100"); - получаем все поля (*) не более 100 записей у которых id=1
$r=sql("db.table","select",array("id","text"),"id=1","0,100"); - тоже самое, но с базы берём только поля id и text
while($row=mysql_fetch_assoc($r[res])) echo "$row[id] - $row[text]<br>"; - так мы перебираем полученные строки
$r=sql("db.table","insert",array("name"=>"MyName","text"=>"MyText")); - вставляем в базу запись с $name="MyName" и $text = "MyText"
$r[num] - это ID идентификатор добавленной строки в случае если в базе задан primary key

function sql($table,$type,$fields,$where="",$limit="") {
$time_start=microtime(1);
if(!preg_match("/^[a-z0-9.`_-]+$/i",$table)) return false;
$type=strtolower($type); if(!in_array($type,array("select","insert","update","delete"))) die("Query type $type failed.");
if(strlen($where)) $where="where $where";
if(strlen($limit)) {if(preg_match("/^[0-9,]+$/i",$limit)) $limit="limit $limit"; else die("Query limit $limit failed.");}
if(is_string($fields) && strlen($fields) && !preg_match("/^[a-z0-9, \*\`_-]+$/i",$fields)) die("Query fields $fields failed.");
$setfields=""; $values="";
if(is_array($fields)) {
if($type=="select") $fields=implode(",",$fields);
if($type=="insert") foreach($fields as $k=>$v) {if($setfields) $setfields.=","; $setfields.="`$k`"; if($values) $values.=","; $values.="'".mysql_real_escape_string($v)."'"; }
if($type=="update") foreach($fields as $k=>$v) {if($setfields) $setfields.=","; $setfields.="`$k`='".mysql_real_escape_string($v)."'"; }
}
if($type=="select") $sql="select $fields from $table $where $limit";
if($type=="insert") $sql="insert into $table ($setfields) values ($values)";
if($type=="update") $sql="update $table set $setfields $where $limit";
if($type=="delete") $sql="delete from $table $where $limit";
$res=mysql_query($sql) or die(mysql_error());
if($type=="select") $r=mysql_num_rows($r);
if($type=="insert") $r=mysql_insert_id();
if($type=="update" || $type=="delete") $r=mysql_affected_rows();
$time=round(microtime(1)-$time_start,3);
return array("num"=>$r,"res"=>$res,"time"=>$time);
}

8497
Степан @Trilby
Я конечно даже близко с Димой не стою, когда речь идёт о программировании, но все же попробую разбавить тему своим постом 😀
Идея, которую я нагло утащил у habrastorage.org, но в гуглах реализации не нашел, а именно - загрузка файла на сервер с проверкой контрольной суммы и присваиванием имени вида md5check.ext
Для чего это нужно? Просто для предотвращения закачки идентичных файлов и создания уникальных имён файлам в одной папке.

Собственно, реализация. В своем примере я просто переберу готовую форму, взятую **********.

Абсолютно нетронутый upload.html
<html>
<head>
<title>Загрузка файлов на сервер</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<h2><p><b> Форма для загрузки файлов </b></p></h2>
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="filename"><br>
<input type="submit" value="Загрузить"><br>
</form>
</body>
</html>

upload.php
<html>
<head>
<title>Результат загрузки файла</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<?php
if($_FILES["filename"]["size"] > 1024*1024*5)
{
echo ("Размер файла превышает 5 МБ");
exit;
}
// Проверяем загружен ли файл
if(is_uploaded_file($_FILES["filename"]["tmp_name"]))
{
// Если файл загружен успешно, перемещаем его
// из временной директории в конечную
$folder = '/home/user/uploadfolder/'; //папка для загрузки файла
$link = 'http://example.com/uploads/'; //её расположение в адресе сайта. Просто для вывода пользователю.
$ext = strtolower(substr(strrchr($_FILES['filename']['name'],'.'), 1)); //расширение файла. Кто знает лучший способ узнать расширение?
$md5filename = md5_file($_FILES["filename"]["tmp_name"]); // проверка md5-суммы загружаемого файла
move_uploaded_file($_FILES["filename"]["tmp_name"], $folder.$md5filename.".".$ext); //перемещение с переименованием файла в md5-сумму.
echo $link.$md5filename.".".$ext; //вывод пользователю ссылки на загруженный файл.
} else {
echo("Ошибка загрузки файла");
}

?>
</body>
</html>

А теперь попробуйте загрузить в форму один и тот же файл пару раз)

Отредактировано Trilby - 16.07.2011
20089
Dimitry @Dimitry
Готовимся к IPv6 - валидация IP адресов

Для общей информации, IPv4 длина от 7-15, IPv6 длина от 3-39.
Функция проверки IP адреса на валидность и протокол.

function checkip($ip) {
$x=explode(".",$ip); $c=count($x);
if($c==4) {$ver=4; for($i=0;$i<$c;$i++) if(!is_numeric($x[$i]) || $x[$i]<0 || $x[$i]>255) $ver=0;}
elseif(preg_match("/^[0-9a-f:]{3,39}$/",$ip)) {$ver=6; $x=explode(":",$ip); $c=count($x); if($c<3 || $c>8) $ver=0; for($i=0;$i<$c;$i++) if(strlen($x[$i])>4) $ver=0; }
return (int)$ver;
}

Пример использования:
if($ver=checkip($_SERVER['REMOTE_ADDR'])) echo "IP-Адрес верный и соответствует протоколу IPv$ver";
else echo "IP-Адрес не верный!";

Так как существуют сокращённые формы записи IPv6 адреса, возможно нам потребуется узнать его полную форму.
Раскрытие сокращённого IPv6 адреса: (например раскрываем ::1 - локальный адрес = 0000:0000:0000:0000:0000:0000:0000:0001 )

function ipv6full($ip) {
$x=explode(":",$ip); $c=count($x);
if($c<8) {$d=str_repeat(":",8-$c); $ip=str_replace("::","::$d",$ip); $x=explode(":",$ip); $c=count($x); }
for($i=0;$i<$c;$i++) if(($l=strlen($x[$i]))!=4) {$d=str_repeat("0",4-$l); $x[$i]=$d.$x[$i];}
return implode(":",$x);
}

20089
Dimitry @Dimitry
Инструкция по переходу с windows-1251 на UTF-8

И так, что нам нужно чтоб перенести сайт на другую кодировку.
Нам нужно перекодировать названия файлов, их содержимое, и содержимое баз данных.
А в некоторых случаях и исправлять движок сайта если он не приспособлен к работе с мультибайтовыми кодировками.
В любом случае лучше всего если у вас есть SSH, и так приступим.

1. Отключаем сайт. Отключим сайт чтобы ничего не нарушилось, а также сделаем перед этим резервную копию.

2. Анализ и автоперекодировка. Перекодируем все файлы с русскоязычными названиями в новую кодировку, а также содержимое для указанных типов файлов.
Для этого я написал не очень сложный скриптик. По умолчанию он выводит файлы которые хочет перекодировать, чтобы выполнить перекодировку нужно нажать на ссылку rename, recode или mbstr set. Последнее в данном случае подставляет "mb_" перед строковыми функциями, делать это нужно только профессионалам!
Закачайте php файл reencoding.php и запустите его:
<?

function scan($dir) {
global $script;
$d = dir ($dir); if(!$d) return;
while(false!==($f = $d->read())) if($f != "." && $f != ".." && $f!=$script) recode($dir."/".$f);
$d->close();
}

function recode($dir) {
global $from,$to,$types;
$enc=iconv($from,"$to//IGNORE",$dir);
if($enc!=$dir) {
echo "<b>FILENAME:</b> $dir => $enc<br>";
if($_GET[rename]) {rename($dir,$enc); $dir=$enc;}
}
if(is_dir($dir)) {scan($dir); return;}
$type=explode(".",$dir); $type=$type[count($type)-1];
if(!in_array($type,$types)) return;
$content=file_get_contents($dir);
$econtent=iconv($from,"$to//IGNORE",$content);
if($econtent!=$content) {
echo "<b>CONTENT:</b> $dir<br>";
if($_GET[recode]) {file_put_contents($dir,$econtent);$content=$econtent;}
}
$mblog=""; $a=explode("\n",$content);

for($i=0;$i<count($a);$i++) {
$a1 = preg_replace('/(\W{1})(strlen|strpos|strrpos|substr|strtolower|strtoupper|stripos|strripos|strstr|stristr|strrchr|substr_count)\(/' ,'$1mb_$2(',$a[$i]);
if($a[$i]!=$a1) $mblog.="<span style='color:gray; font-size:11px;'>".($i+1).": ".htmlspecialchars($a[$i])."</span><br>";
if(preg_match("/(utf-8|utf8|cp1251|windows-1251)/i",$a[$i])) echo "<b>Encoding used</b>: $dir - <span style='color:blue; font-size:11px;'>".($i+1).": ".htmlspecialchars($a[$i])."</span><br>";
if(preg_match("/(preg_)/i",$a[$i])) echo "<b>Preg used</b>: $dir - <span style='color:green; font-size:11px;'>".($i+1).": ".htmlspecialchars($a[$i])."</span><br>";
}

if($mblog) echo "<b>MBSTR CHECK</b>: $dir<br>$mblog";
if($_GET[mbstrset] && $mblog) {
$content = preg_replace('/([[:^alpha:]]{1})(strlen|strpos|strrpos|substr|strtolower|strtoupper|stripos|strripos|strstr|stristr|strrchr|substr_count)\(/' ,'$1mb_$2(',$content);
file_put_contents($dir,$content);
}
}

$script="reencoding.php";
$from="windows-1251";
$to="utf-8";
$types=array("php","html"); //file types to encode content
$dir="./";
scan($dir);

echo "<br><a href=?>CHECK ALL</a> | <a href=?rename=1>RENAME FILES</a> | <a href=?recode=1>RECODE CONTENT</a> | <a href=?mbstrset=1>MBSTR SET FUNCTIONS</a><br><br>";
if($_GET[rename]) echo "<b>RENAME COMPLETE</b><br>";
if($_GET[recode]) echo "<b>RECODE COMPLETE</b><br>";
if($_GET[mbstrset]) echo "<b>MBSTR SET COMPLETE</b><br>";

?>

3 MB_STR функции и не только. Наши старые PHP функции для работы со строками не годятся, им нужны приставки mb_ , можно воспользоваться скриптом поиска таких функций и заменить их на новые с mb_ автоматически. (только для опытных) Также чтобы не задавать кодировку в каждой такой функции, нужно указать её в конфиге сайта по умолчанию так:
mb_internal_encoding("utf-8");
Но и это ещё не всё, скрипт также покажет вам и все найденные "preg_" функции, дело в том что если в таких функциях используются не латинские символы, то необходимо добавить модификатор u. Например так:
preg_match("/^[a-zа-я]+$/u"$str)
Кроме этого, возможны и другие функции которые необходимо доработать под UTF-8, но на данный момент это самые важные.

4. Базы данных. Желательно перекодировать базу в UTF-8, но для начала мы можем просто включить для PHP связь с базой (только MySQL5) в кодировке UTF-8, для этого в коде после подключения к базе (mysql_connect) достаточно прописать или изменить такую строку:
mysql_query("SET NAMES 'utf8'");

Если вы всё таки нужно перекодировать базу в UTF-8, то для каждой таблицы нужно выполнять этот запрос:
ALTER TABLE `db_name`.`table_name` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci

5. META и Header заголовки. Ну и на последок меняем кодировку для HTML шаблонов, в PHP заголовках и в mail() заголовках.
Выше приведённый скрипт сам найдёт все места где указана старая кодировка (но только в файлах поиска), например:
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />
меняем на
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
или
Content-Type: text/plain; charset="windows-1251"
меняем на
Content-Type: text/plain; charset="utf-8"

20089
Dimitry @Dimitry
Как защитить сайт и сервер от перегрузки из-за DDOS атак
(поисковые боты также могут быть заблокированы, поэтому надо добавлять их IP в исключения, самые важные я добавил)

Достаточно добавить данный код после <? в самый верх атакуемой страницы, обычно это index.php
Красный параметр означает что за 1 секунду открыть страницу сайта с одного IP можно только 1 раз,
если поставить 2, то сайт можно будет открывать только 1 раз в 2 секунды, это улучшает защиту!

function checkddos($sec) {
$ban=0; $file="protect.dat"; $time=time(); $ip=$_SERVER[REMOTE_ADDR];
$whitelist=array("127.0.0.1","91.42.*.*","217.235.*.*","213.180.*.*","87.250.*.*","77.88.*.*","66.249.*.*","188.72.*.*");
$x=explode(".",$ip); foreach($whitelist as $ip1) if(preg_match("/^$x[0]\.($x[1]|\*)\.($x[2]|\*)\.($x[3]|\*)$/",$ip1)) return 0;
$f=@fopen($file,"r"); if($f) {clearstatcache(); flock($f,LOCK_SH); $r=@fread($f,filesize($file)); fclose($f);}
$a=unserialize($r);
if($a[$ip]+$sec>=$time) $ban=1; $a[$ip]=$time;
foreach($a as $k=>$v) if($v+$sec+1<$time) unset($a[$k]);
file_put_contents($file,serialize($a),LOCK_EX);
return $ban;
}
if(checkddos(1)) die("503 Service not available");

20089
Dimitry @Dimitry
Получение информации о состоянии Shoutcast 2 сервера, название песни и так далее

Так как данный сервер не поддерживается разработчиками, я отказался от его использования в пользу Icecast 2.
Тем не менее данный код может быть полезен тем кто всё ещё использует этот сервер.

<?
//SHOUTCAST 2 parsing
function shoutcast2($server,$port,$sid=1) {
function filter($str) {return htmlspecialchars($str);}
$info=array();
$info[port]=$port;
$info[server]="ShoutCast2";
//get html
$html=req("http://$server:$port/index.html?sid=$sid","",0,3,0);
//parse
$a=explode('valign="top">',$html);
$a[0]="";$end=explode("</b>",$a[count($a)-1]); $a[count($a)-1]=$end[0];
//filter
for($i=1;$i<count($a);$i++) {
$a[$i]=str_replace('<font class="default">','',$a[$i]);
$x=explode(': ',$a[$i]); $name=$x[0];
$var=strip_tags($x[1]); //clear tags
//set my vars
if($name=="Server Status") {if(substr_count($var,"Server is currently up")) $info[online]=1;}
//Stream is up at 128 kbps with 0 of 10 listeners (0 unique)
if($name=="Stream Status") {$x=explode(" ",$var); $info[kbps]=(int)$x[4]; $info[listeners]=(int)$x[7]; $info[limit]=(int)$x[9]; $info[ulisteners]=(int)substr($x[11],1); }
if($name=="Listener Peak") $info[plisteners]=filter($var);
if($name=="Stream Name") $info[djname]=mb_substr(filter($var),0,50);
if($name=="Current Song") $info[song]=filter($var);
if($name=="Stream Genre") $info[genre]=filter($var);
if($name=="Stream ICQ") $info[icq]=filter($var);
if($name=="Stream AIM") $info[aim]=filter($var);
if($name=="Stream URL") $info[url]=filter($var);
}
return $info;
}

//Пример использования функции:
$info=shoutcast2("radioserver.ru",8000,1);
print_r($info);

?>

В качестве бонуса, пример конфига сервера sc_serv.conf:
MaxUser=100
Password=djhiddenpass
PortBase=8000
ScreenLog=0
W3CEnable=No
W3CLog=sc_w3c.dat
LogFile=sc_servlog.dat
SrcIP=ANY
DestIP=ANY
Yport=80
NameLookups=0
AdminPassword=adminhiddenpass
AutoDumpUsers=0
AutoDumpSourceTime=30
IntroFile=intro%d.mp3
TitleFormat=%s
URLFormat=%s
PublicServer=No
AllowRelay=Yes
AllowPublicRelay=No
#relay server commented
#yp2=1
#RelayServer=relayradio.ru[host]
#RelayPort=8000[port]
#streamid=1

Ну и самая новая версия Shutcast 2 севрера:
**********

20089
Dimitry @Dimitry
Приводим старый PHP код с <? в порядок

Для правильной подсветки и с учётом на будущее, лучше не использовать открытие php с помощью <? или <?=, а использоваться только <?php. Данная команда поможет рекурсивно найти все места в вашем проекте где есть сокращённый вид открытия php кода. Нужно зайти в папку проекта через ssh и выполнить:

cd /home/user/website.ru
egrep -s -R -e '<\?[e=[:space:]]{1}' -e '<\?$' ./

Совет на будущее

Хотите без проблем и эскейпов вставлять HTML код с PHP переменными прямо в php скрипт, воспользуйтесь способом hededoc.
Пример с вставкой простых переменных и элементов массива:
<?php

$number=15;
$a=array('name'=>'Vasya','years'=>25);

//тут вставляем HTML код
echo <<<HTML

Тут можно писать любые кавычки, например "эти" или 'эти'.
Эй, привет {$a['name']}, как дела?
Твой номер $number, да?

HTML;

?>