Работа со временем. Получение диаппазонов текущей и прошлой недели

<?php
/**
 * 
 */
 
//понедельник на этой неделе
echo date('d.m.Y', strtotime(date('Y').'W'.date('W')));
echo ' - ';
//воскресенье на этой неделе
echo date('d.m.Y', strtotime(date('Y').'W'.date('W').'-7'));
 
echo '<br />'.PHP_EOL;
 
//прошлую неделю можно получить просто вычитая неделю от предыдущих расчетов    
echo date('d.m.Y', strtotime(date('Y').'W'.date('W').' - 1 week'));
echo ' - ';
echo date('d.m.Y', strtotime(date('Y').'W'.date('W').'-7 - 1 week'));
24 декабря 2010, 02:36

Защита от sql инъекций при помощи pdo_mysql

<?php
/**
 * Защита от sql инъекций при помощи pdo_mysql
 * автор: Nc_Soft
 * 19.12.10
 */

$host = 'localhost'; //хост
$db = 'database_name'; //база данных
$user = 'root'; //юзер
$password = 'password'; //пароль

//соединяемся
$db = new PDO("mysql:host=$host;dbname=$db", $user, $password, 
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));  

//делаем sql запрос на создание таблицы (id|user|time)
$q = $db->prepare("CREATE TABLE IF NOT EXISTS `test` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `user` varchar(20) NOT NULL,
  `time` timestamp NOT NULL default CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8; ");

//выполняем запрос
$q->execute();

//теперь давайте добавим запись
$q = $db->prepare("INSERT INTO test SET user=? ");
$q->execute(array('имя1'));

/*
в таблице добавилась запись
обратите внимание, что я не использовал никакие функции для фильтрации
(mysql_real_escape_string и подобные), просто обозначит placeholder куда вставить 
значение через ?,  а потом при execute задал значение массивом
*/

//давайте теперь изменим добавленную запись
//получаем последний добавленный ид
$id = $db->lastInsertId(); 

//запрос на update
$db->prepare("UPDATE test SET user=? WHERE id=? ")->execute(array("новое ' имя", $id));

/*
Обратите внимание, сейчас я воспользовался цепочкой вызовов ->()-> 
чтобы не заводить переменную $q как в примерах выше.
Параметры в массиве должны идти в строгом порядке, как в запросе, 
действительно, будет нелепо перепутать id и name местами ;)
Даже не смотря на то, что в параметре присутствует кавычка запрос выполянется нормально, 
pdo все экранирует самостоятельно.
*/

//если не нравятся ? или хотите изменить порядок, можно заюзать именнованные параметры
$db->prepare("INSERT INTO test SET user=:user ")->execute(array(':user'=>'новый юзер'));
/*
Теперь массив с параметрами не такой безликий как раньше, какой способ задания параметров 
выбрать решайте сами
*/

//Ну и напоследок: как извлекать записи
$q = $db->prepare("SELECT * FROM test");
$q->execute();
$data = $q->fetchAll();

print_r($data);

//подробную информацию о pdo_mysql вы всегда можете найти в гугле
19 декабря 2010, 16:44

Реализация json_encode

<?php
/**
 * Реализация json_encode
 * автор: Alexmuz (http://alexmuz.ru/)
 * 18.09.10
*/

if (!function_exists('json_encode')) {  
    function json_encode($value) 
    {
        if (is_int($value)) {
            return (string)$value;   
        } elseif (is_string($value)) {
	        $value = str_replace(array('\\', '/', '"', "\r", "\n", "\b", "\f", "\t"), 
	                             array('\\\\', '\/', '\"', '\r', '\n', '\b', '\f', '\t'), $value);
	        $convmap = array(0x80, 0xFFFF, 0, 0xFFFF);
	        $result = "";
	        for ($i = mb_strlen($value) - 1; $i >= 0; $i--) {
	            $mb_char = mb_substr($value, $i, 1);
	            if (mb_ereg("&#(\\d+);", mb_encode_numericentity($mb_char, $convmap, "UTF-8"), $match)) {
	                $result = sprintf("\\u%04x", $match[1]) . $result;
	            } else {
	                $result = $mb_char . $result;
	            }
	        }
	        return '"' . $result . '"';                
        } elseif (is_float($value)) {
            return str_replace(",", ".", $value);         
        } elseif (is_null($value)) {
            return 'null';
        } elseif (is_bool($value)) {
            return $value ? 'true' : 'false';
        } elseif (is_array($value)) {
            $with_keys = false;
            $n = count($value);
            for ($i = 0, reset($value); $i < $n; $i++, next($value)) {
                        if (key($value) !== $i) {
			      $with_keys = true;
			      break;
                        }
            }
        } elseif (is_object($value)) {
            $with_keys = true;
        } else {
            return '';
        }
        $result = array();
        if ($with_keys) {
            foreach ($value as $key => $v) {
                $result[] = json_encode((string)$key) . ':' . json_encode($v);    
            }
            return '{' . implode(',', $result) . '}';                
        } else {
            foreach ($value as $key => $v) {
                $result[] = json_encode($v);    
            }
            return '[' . implode(',', $result) . ']';
        }
    } 
}
18 сентября 2010, 22:11

Включаем кэширование через .htaccess

# Включаем кэширование через .htaccess
# Автор: Nc_Soft
# 06.09.10

FileETag MTime Size
<ifmodule mod_expires.c>
<filesmatch ".(jpg|gif|png|css|js)$">
ExpiresActive on
ExpiresDefault "access plus 1 year"
</filesmatch>
</ifmodule>

#можете прописать это на своем хостинге
#например, на jino.ru это ускоряет загрузку сайта
#(отдельный вопрос к хостерам, которые не ставят заголовки кэширования на статику, ну да фиг с ними)
6 сентября 2010, 13:01

Работа с .tar.gz

<?php
/* Я постоянно забываю эти долбаные ключи, поэтому публикую сюда */

exec('tar -cvf file.tar /full/path');  //создать .tar
exec('tar -czvf file.tar.gz /full/path'); //создать .tar.gz (архив)
exec('tar -cjvf file.tar.bz2 /full/path'); //создать .tar.bz2 (архив)

exec('tar -xvf file.tar.gz'); //распаковка
19 июля 2010, 18:43

Фильтрация операторов по ip диаппазонам

<?php
/**
 * Фильтрация операторов по ip диаппазонам
 * автор: Nc_Soft
 * 13.05.10
 */

/*
Часто возникает задача фильтровать трафик в зависимости от оператора.
Можно хранить диаппазоны в базе данных и выбирать оттуда, но для их редактирования
надо либо писать некую админку, либо залазить в phpmyadmin или в подобные вещи.
Предлагаю простенький фильтр, который можно легко и гибко редактировать, 
задавая как диаппазоны, так и одиночные ип адреса. Причем, абсолютно не важен формат записи, 
главное чтобы присутствовал ип адрес. Это позволяет простым копипастом вставлять диаппазоны.
Главное условие - не более 2 ип адресов в строке.
Для примера задаю для мтс и билайна.
*/

//замеряем скорость (об этом ниже)
define('START_TIME',microtime(true));

//функция фильтра, в ней можно редактировать ип адреса
function traf_filter($ip) {
	$opsos = array(
	'beeline' => ' --- ниже можно редактировать ---
	
[217.118.66.0 - 217.118.66.255] //GPRS Core Москва 
[217.118.81.0 - 217.118.81.255] //GPRS Core Ростов-на-Дону
[217.118.78.0 - 217.118.78.255] //GPRS Core Санкт-Петербург
[217.118.79.0 - 217.118.79.255] //GPRS Core Новосибирск
[217.118.91.0 - 217.118.91.255] //GPRS Core Екатеринбург
[217.118.90.0 - 217.118.90.255] //GPRS Core Саратов
[217.118.64.0 - 217.118.64.255] //GPRS Core Хабаровск
[217.118.82.0 - 217.118.82.255] //GPRS Core Ставрополь
[217.118.83.0 - 217.118.83.255] //GPRS Core Челябинск
[217.118.93.0 - 217.118.93.255] //GPRS Core Н.Новгород
[217.118.92.0 - 217.118.92.255] //GPRS Core Череповец
[217.118.95.0 - 217.118.95.255] //GPRS Core Воронеж
[213.252.195.0 - 213.252.195.255] //GPRS Core Калининград
[83.220.227.0 - 83.220.227.255] //GPRS Core Самара
[217.118.89.0 - 217.118.89.255] //GPRS Core Сахалин
[85.115.243.32 - 85.115.243.63] //GPRS Core Иркутск
Beeline (WAP) - [217.118.85.64 - 217.118.85.79]

--- выше можно редактировать ---',

'mts' => '   --- ниже можно редактировать ---

194.54.148.8
213.87.6.8
217.8.235.194
217.8.236.11
217.74.244.13
217.66.145.10
217.66.145.15
213.87.72.73
213.87.72.87
212.92.139.198
195.74.84.32
80.83.238.246
80.83.238.247
80.83.232.0 - 80.83.233.255
80.83.228.0 - 80.83.231.255
80.83.238.0 - 80.83.238.255
80.83.239.1 - 80.83.239.12
84.17.254.0 - 84.17.255.255
95.153.191.0 - 95.153.191.255
195.22.110.0 - 195.22.110.255
195.74.84.36 - 195.74.84.47
195.74.84.74
195.74.84.128 - 195.74.84.223
195.85.238.168 - 195.85.238.223
213.87.8.0 - 213.87.15.255
213.87.64.0 - 213.87.64.63
213.87.64.128 - 213.87.64.255
213.87.76.128 - 213.87.76.255
213.87.77.0 - 213.87.77.255
213.87.80.0 - 213.87.81.255
213.87.82.0 - 213.87.85.255
213.87.86.160 - 213.87.86.195
213.87.87.0 - 213.87.88.255
213.87.89.0 - 213.87.90.255
213.87.92.0 - 213.87.95.255
215.66.146.1 - 215.66.146.32
217.8.225.0 - 217.8.225.255
217.8.226.0 - 217.8.227.255
217.8.228.0 - 217.8.229.255
217.8.230.0 - 217.8.231.255
217.8.232.0 - 217.8.233.255
217.8.234.0 - 217.8.234.255
217.8.236.0 - 217.8.236.255
217.8.239.0 - 217.8.239.255
217.66.146.1-217.66.146.99
217.66.147.0 - 217.66.147.255
217.74.249.0 - 217.74.251.255
217.74.247.128 - 217.74.247.191
217.74.244.128 - 217.74.244.255
217.74.245.0 - 217.74.245.255
217.74.248.0 - 217.74.248.255
217.74.247.192 - 217.74.247.223

--- выше можно редактировать ---	',
);

//числовое представление экзаменуемого ип
$ip = sprintf('%u', ip2long($ip));

//ищем оператора
foreach ($opsos as $oper=>$v) {
	$s = explode("\n", trim($v));

	foreach ($s as $p) {
		$arr = array();
		//ищем ип адреса в строке
		preg_match_all('`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`', $p, $arr);
		if (!count($arr[0])) continue;

		$start = $arr[0][0];
		//если ип адресов в строке 2, то это диаппазон
		$end = isset($arr[0][1]) ? $arr[0][1] : $start;

		//сверка
		if ($ip >= sprintf('%u', ip2long($start)) && $ip <= sprintf('%u', ip2long($end)) ) {
			return $oper;
		}
	}
}

//если ничего не найдено возвращаем пустоту
return ;
}

//применение очень простое
echo traf_filter('195.85.238.213'); //mts

//ну и посмотрим сколько времени пахал скрипт
printf('%.4f sec', microtime(true) - START_TIME); //~0.004 сек

/*
Любители оптимизации, конечно, могут меня пожурить, потому что используются регулярки,
да еще и в цикле. Но ведь всегда можно применить кэширование этого массива + ставить куку тем, 
для кого уже определили оператора.

p.s если вам понравился этот фильтр, то можете меня слегка отблагодарить R167883193132 ;)
*/
13 мая 2010, 16:33

Определение параметров мобильного устройства через яндекс api

<?php 
/**
 * Определение параметров мобильного устройства через яндекс api
 * автор: Nc_Soft
 * 21.04.10
 */

/*
Дока http://api.yandex.ru/detector/doc/dg/concepts/About.xml
но пример для пхп там на данный момент неверный, вот мой вариант
*/

$headers = array();
$hmask = array(
'profile',
'wap-profile',
'x-wap-profile',
'user-agent',
'x-operamini-phone-ua',
);

foreach ($_SERVER as $key => $value) {
	if (strpos($key, "HTTP_") === 0) {
		$field = substr($key, 5);
		$field = strtolower($field);
		$field = str_replace('_', '-', $field);
		if (in_array($field, $hmask)) $headers[$field] = $value;
	}
}

$ch = curl_init('http://phd.yandex.net/detect?'.http_build_query($headers));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$res = curl_exec($ch);
curl_close($ch);
unset($headers);
echo $res;

/*
про ответы сервера можно почитать тут
http://api.yandex.ru/detector/doc/dg/concepts/detector-response.xml

И, пожалуйста, кэшируйте запросы к апи, не долбите яндекс :)
*/
?>
21 апреля 2010, 19:14

Рекурсивное удаление дерева каталогов SPL

<?php
/**
 * Рекурсивное удаление дерева каталогов SPL
 * автор: NC_Soft
 * 24.03.10
 */
$items = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('D:/three'), RecursiveIteratorIterator::CHILD_FIRST);
foreach($items as $item){
	if ($item->isDir()){
		rmdir($item->getRealPath());
	}else{
		unlink($item->getRealPath());
	}
}
?>
24 марта 2010, 07:54

Получение диаппазона ip по маске

<?php
/**
 * Получение диапазона ip по маске
 * автор: Nc_Soft
 * 01.03.10
 */

$ip = '217.118.66.0/24';

$mask = split('/', $ip);
$start = sprintf('%u', ip2long($mask[0]));
$end = $start + pow(2, 32-$mask[1]) - 1;

echo 'Искомый диаппазон: ';
echo long2ip($start);
echo ' - ';
echo long2ip($end);


//обратное преобразование
$start = '217.118.66.0';
$end = '217.118.66.255';
$mask = 32 - log(sprintf('%u', ip2long($end)) - sprintf('%u', ip2long($start)) + 1, 2);
$mask = floor($mask);

echo PHP_EOL.'маска = '.$mask;
/*
 Зачем это всё надо? 
 -Записывать диаппазоны через маску короче
 -Чтобы закрыть доступ через .htaccess к диаппазону ip надо писать через маску
 deny from 217.118.66.0/24
 */
1 марта 2010, 15:11

wordwrap для многобайтовых кодировок

<?php
/**
 * wordwrap для многобайтовых кодировок
 * автор: Megido
 * 20.02.10
 */

function mb_wordwrap($str, $width=75, $break="\n", $cut=false, $charset="null") {
	if ($charset == "null") $charset = mb_internal_encoding();
	$pieces = split($break, $str);
	$result = array();
	foreach ($pieces as $piece) {
		$current = $piece;
		while ($cut && mb_strlen($current) >$width) {
			$result[] = mb_substr($current, 0, $width, $charset);
			$current = mb_substr($current, $width, 2048, $charset);
		}
		$result[] = $current;
	}
	return(implode($break, $result));
}

echo mb_wordwrap($mb_string, 16, "<br/>", true, "utf-8");

?>
20 февраля 2010, 16:45

Ресайз (resize) gif анимации

<?php
/**
* Ресайз (resize) gif анимации
* автор: Nc_Soft
* 08.02.10
*/

/* Если использовать GD, то вы заметите, что ресайза анимашки
как такового не выйдет, будет изменен лишь первый кадр.
На помощь приходит ImageMagick (http://www.imagemagick.org/)

В мануале http://www.php.net/manual/en/imagick.examples-1.php  приведен пример
(смотрите Example #5 Read in GIF image and resize all frames), который делает
косячные анимашки, поэтому привожу рецепт, который работает.
*/

//большая анимашка big.gif
$images = new Imagick('big.gif');

//вычисляем масштаб сторон (хотим сделать с максимальной стороной 64)
$scale  = max($images->getImageWidth(), $images->getImageHeight()) / 64;

//вот этой фишки не хватает в примере из мануала на php.net
$images = $images->coalesceImages();

//вычисляем рамеры сторон с учетом масштаба
$width  = round($images->getImageWidth()  / $scale);
$height = round($images->getImageHeight() / $scale);

//и ресайзим каждый кадр в цикле
do {
        $images->scaleImage($width, $height);
} while ($images->nextImage());

//оптимизируем слои
$images->optimizeImageLayers();

//освобождаем память
$images = $images->deconstructImages();

//сохраняем анимацию в small.gif
$images->writeImages('small.gif', true);

/*
В результате получаем нормальную отресайзенную анимацию.
Но если попытаться сделать пакетную обработку нескольких анимашек, то
можно убедиться, что скрипт делает это ОЧЕЕЕЕЕНЬ ДОЛГО, поэтому для
пакетной обработки лучше применять вызов команды
*/
exec("/usr/local/bin/convert 'big.gif' -coalesce -thumbnail '64x64>' \
				-layers Optimize  'small.gif' ");

/**
Что же делать, если нет ImageMagick на хостинге?
Для экстремалов есть классы для работы  с gif-анимациями, если хотите, можете
писать о них в комментах, лично у меня такого желания нет.
*/
8 февраля 2010, 20:17

Создание дампа mysql при помощи mysqldump

<?php
/**
 * Создание дампа mysql при помощи mysqldump
 * автор: DEATH
 * 07.02.10
 */

//очень полезно ставить на крон
$name = date("d.m.Y_H-i-s");
exec("mysqldump --user=имя_пользователя_бд --password=пароль --default-character-set=кодировка_данных имя_базы > dump_$name.sql");
Перенаправление вывода с mysqldump в gzip, bzip2, lzma
Пример для gzip сжатия
mysqldump < mysqldump options> | gzip > outputfile.sql.gz

С помощью gunzip импортируем сжатий дамп gzip-ом
gunzip < outputfile.sql.gz | mysql < mysql options>

Сжимаем вывод mysqldump-a используя архиватор bzip2
mysqldump < mysqldump options> | bzip2 > outputfile.sql.bz2

Импортируем обратно:
Bunzip2 and import using bzip2
bunzip2 < outputfile.sql.bz2 | mysql < mysql options>

Делаем mysql дамп и напрямую сжимаем его с помощью lzma
mysqldump < mysqldump options> | lzma > outputfile.sql.lzma

Импорт
unlzma < outputfile.sql.lzma | mysql < mysql options>

7 февраля 2010, 02:41

Обход защиты скриптов, завязанных на доменное имя

<?php
/**
* Обход защиты скриптов, завязанных на доменное имя
* автор: Nc_Soft
* 20.01.09
*/
?>
Ситуация: Имеется некий скрипт, исходный код которого вам недоступен
(например закодировано в зенд и вы не можете задезендить)
при обращении выдаёт что-то вроде "запрещенный домен"
тоесть он завязан на домен каким-то условием , скорее всего таким
if ($_SERVER['HTTP_HOST'] != 'site.ru') die('запрещенный домен');
На домене site.ru скрипт работает замечательно, а на другом естественно нет.
Создаём для теста файл test.php c нашим условем

<?php
if ($_SERVER['HTTP_HOST'] != 'site.ru') die('запрещенный домен');
echo 'Проверка пройдена, скрипт выполняется';
?>

при запуске естественно выдается запрещенный домен
Чтобы обойти проверку создайте .htaccess в этой же директории вида

php_value auto_prepend_file c:\fint.php

путь к файлу должен быть полным!!
а в файле c:\fint.php пишем

<?php $_SERVER['HTTP_HOST'] = 'site.ru'; ?>

После фальсификации переменной $_SERVER['HTTP_HOST'] скрипт будет работать на любом домене
20 января 2010, 13:10

Обрезка видео ffmpeg

<?php
/**
* Обрезка видео ffmpeg
* автор: Nc_Soft
* 19.01.10
*/

//отрежем 1 минуту от начала
exec('ffmpeg -i video.avi -vcodec copy -acodec copy -ss 00:00:00 -t 00:01:00 trim_video.avi');
19 января 2010, 14:55

Установка chmod всем папкам и директориям

<?php
/**
* Установка chmod всем папкам и директориям
* автор: Nc_Soft
* 13.01.10
*/

//обработка файлов (666)
exec('find . -type f -exec chmod 666 \{\} \; ');

//обработка папок (777)
exec('find . -type d -exec chmod 777 \{\} \; ');
13 января 2010, 18:53

Перепаковка jar файла

<?php
/**
* Перепаковка jar файла
* автор: Nc_Soft
* 11.01.10
*/

/*
Задача: изменить имя игры при установки с Worms на Worms snippets.pp.ru
*/

//исходный файл
$file = 'Worms.jar';

//создаем объект
$z = new ZipArchive();

//открываем архив с возможностью перезаписи
if (!$z->open($file, ZIPARCHIVE::OVERWRITE)) die('Не удалось открыть архив');

//далее извлекаем MANIFEST.MF
$mf = '';
$manifest = 'META-INF/MANIFEST.MF';
$fp = $z->getStream($manifest);
if(!$fp) {
	//манифест еще может быть здесь Meta-inf/Manifest.mf
	$manifest = 'Meta-inf/Manifest.mf';
	$fp = $z->getStream($manifest);
	if (!$fp) {
		die('не удалось извлечь манифест');
	}
}

//читаем данные
while (!feof($fp)) {
	$mf .= fread($fp, 2000);
}
fclose($fp);

echo $mf;

/* Получаем вот это

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.2
Created-By: 1.4.2_06-b03 (Sun Microsystems Inc.)
MIDlet-Name: Worms Forts Etty 2D
MIDlet-Vendor: THQ.Etty
MIDlet-1: Worms Forts, /Icon_15x15.png, CMIDlet
MIDlet-Version: 1.0.1
MIDlet-Icon: /Icon_15x15.png
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-2.0

*/

//дополняем название игры
$mf = preg_replace('`MIDlet-Name:\s+([^\r\n]+)`i', 'MIDlet-Name: \\1 snippets.pp.ru', $mf);

//и теперь самое главное! заменяем файл манифеста в архиве
//разумеется у архива должны быть права на запись
$z->addFromString($manifest, $mf);
$z->close();

//пробуем качать и ставить в телефон, у меня запускается, а у вас?
11 января 2010, 07:24

Float и Double при BETWEEN в mysql

# Float и Double при BETWEEN в mysql
# автор: Nc_Soft
# 04.01.10

CREATE TABLE `t` (
  `s_float` float(8,2) NOT NULL,
  `e_float` float(8,2) NOT NULL,
  `s_double` double(8,2) NOT NULL,
  `e_double` double(8,2) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records 
-- ----------------------------
INSERT INTO `t` VALUES ('1.12', '5.67', '1.12', '5.67');

#надо выбрать диаппазон, в который попадает число 1.12, ничего сложного?

SELECT * FROM t WHERE 1.12 BETWEEN s_float AND e_float

#получаем в результате 0 записей, хотя диаппазон такой есть
#чтобы не было проблем тип поля при такой выборке должен быть double, а не float

SELECT * FROM t WHERE 1.12 BETWEEN s_double AND e_double

#в результате выбрался желанный диаппазон
4 января 2010, 20:46

Удаление дубликатов записей в MYSQL

##
# Удаление дубликатов записей в MYSQL
# автор: Nc_Soft
# 30.12.09
##

#допустим, в таблице tbl имеется поле url и надо удалить все записи,
#чтобы url присутствовал в единственном экземпляре.
#Для этого необходимо поставить уникальный индекс на url с игнором

ALTER IGNORE TABLE tbl ADD UNIQUE (url)

#сделать копию таблицы (без индексов) можно так
CREATE TABLE copy_tbl SELECT * FROM tbl
30 декабря 2009, 09:23

Получение ip базы logofon

<?php
/**
 * Получение ip базы логофона
 * автор: Nc_Soft
 * 11.12.09
 */

//переменная содержащая время обновления базы
$GLOBALS['last_mod'] = '';

//открываем сеанс curl
$ch = curl_init('http://www.logofon.ru/xml/ips.xml');
curl_setopt($ch, CURLOPT_USERAGENT, 'snippets ip bot :)');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

//функция обратного вызова, которая будет проверять заголовки
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'curlHeaderCallback');

//получение данных
$xml_data = curl_exec($ch);
//закрываем curl
curl_close($ch);

//функция обратного вызова, ищет Last-Modified
function curlHeaderCallback($ch, $header) {
	//чекаем Last-Modified
	$s = explode(': ', $header, 2);
	if ($s[0] == 'Last-Modified') $GLOBALS['last_mod'] = trim($s[1]);

	return strlen($header);
}

/*Имея $GLOBALS['last_mod'] в таком виде: Mon, 07 Dec 2009 21:43:14 GMT
мы можем проверять актуальность нашей базы, чтобы не обновляться лишний раз

для справки: чтобы получить timestamp надо сделать так
echo strtotime($GLOBALS['last_mod']);
*/

//допустим, надо обновиться, для этого парсим xml файл
//для примера выведу всех опсосов в табличках
//в качестве парсера юзаем правильные функции, а не регулярки!!!
$xml = simplexml_load_string($xml_data);

foreach ($xml->operator as $opsos) : ?>
	<hr />
	<table border="1">
	<tr>
	<td>ид</td>
	<td>опсос</td>
	<td>страна</td>
	<td>сокращение страны</td>
	</tr>
	
	<tr>
	<td><?=$opsos['id'];?></td>
	<td><?=$opsos['name'];?></td>
	<td><?=$opsos['country'];?></td>
	<td><?=$opsos['tld'];?></td>
	</tr>

	<?php
	//выводим диаппазоны
	foreach ($opsos->range as $range) : ?>
		<tr>
		<td colspan="2"><?=long2ip($range['ip1']);?></td>
		<td colspan="2"><?=long2ip($range['ip2']);?></td>
		</tr>
	<?php endforeach; ?>
	</table>
<?php endforeach;

/*
Как видите, все просто и удобно.
А при помощи этого сниппета можно легко импортировать
эту базу в свои проекты
*/
11 декабря 2009, 08:44

Применение Google Image Api

<?php
/**
 * Применение Google Image Api
 * автор: Nc_SOft
 * 25.11.09
 */

/*
Не знаю как вас, а меня изрядно подзаебали умники, продающие
"воздух" под громким названием глобальный поиск картинок
*/

$search = 'Сиськи Семенович';
$json = file_get_contents('http://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=large&q='.urlencode($search).'&start=0');
$data = json_decode($json);

//смотрим с чем имеем дело 
//print_r($data); 
//и на вывод

?><div>результатов: <?=$data->responseData->cursor->estimatedResultCount;?></div>
<?php foreach ($data->responseData->results as $v) : ?>
<div><a href="<?=$v->unescapedUrl;?>"><img src="<?=$v->tbUrl;?>" /></a></div>
<?php endforeach; 

//для самостоятельной работы: 
//http://code.google.com/intl/ru/apis/ajaxsearch/documentation/reference.html#_intro_fonje
25 ноября 2009, 10:40