Получение диаппазона 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

Определение номера телефона посетителя

<?php
/**
* Определение номера телефона посетителя
* автор: Nc_Soft
* 21.11.09
*/

//заголовки которые следует проверить

$phone_headers = array('HTTP_MSISDN',
                       'HTTP_X_MSISDN',
                       'HTTP_X_NOKIA_MSISDN',
                       'HTTP_X_WAP_NETWORK_CLIENT_MSISDN',
                       'HTTP_X_UP_CALLING_LINE_ID',
                       'HTTP_X_NETWORK_INFO');
$phone = '';

foreach ($phone_headers as $key) {
    if (isset($_SERVER[$key]) ) {
	    $arr = array();
        //находим нечто похожее на номер
        preg_match('`\d{5,20}`', $_SERVER[$key], $arr);
        if ($arr[0]) {
          $phone = $arr[0];
          break;
        }
    }
}

echo "номер - $phone";

//естественно, работает только у тех, кто лазает по вап профилю
21 ноября 2009, 23:11

Выдача удаленного файла скриптом с докачкой

<?php
/**
 * Выдача удаленного файла скриптом с докачкой
 * автор: Nc_Soft
 * 26.10.09
 */

//урл удаленного файла
$url = 'http://snippets.pp.ru/1.mp3';

//инициализация сеанса curl
$ch = curl_init($url);

//если клиент запрашивает докачку
if(isset($_SERVER['HTTP_RANGE'])) {
	curl_setopt($ch, CURLOPT_RANGE, str_replace('bytes=', '', $_SERVER['HTTP_RANGE']));
}

//бинарные данные
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);

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

//падаем в случаи ошибки
curl_setopt($ch, CURLOPT_FAILONERROR, 1);

//браузер
curl_setopt($ch, CURLOPT_USERAGENT, 'Opera/9.80 (Windows NT 5.1; U; ss; MRA 5.4 (build 02647); ru) Presto/2.2.15 Version/10.00');

//accept браузера
$info = array(
'Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1',
'Accept-Language: ru-RU,ru;q=0.9,en;q=0.8',
'Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1',
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $info);

//запуск
curl_exec($ch);

function curlHeaderCallback($ch, $strHeader) {
	//выдаем такой же заголовок, как и удаленный сервер, где лежит файл.
	//заголовки идут по порядку
	header($strHeader);
	return strlen($strHeader);
}

//запустив скрипт вы можете выдать удаленный файл через свой сайт.
//а чтобы файл нормально сохранялся, а не с адресом скрипта, 
//надо настроить mod_rewrite, чтобы на запрос блаблабла/file.mp3 выдавался этот скрипт
26 октября 2009, 03:58

Определение корректности кодировки

<?php
/**
 * Определение корректности кодировки
 * автор: Nc_Soft
 * 20.10.09
 */

/*
чтобы определить корректность кодивки 
могу порекомендовать вот такой способ
*/

$text = 'здесь текст';

if (!mb_check_encoding($text, 'utf-8')) {
	echo 'Символы некорректны для utf-8';
}

/*этот метод не определяет кодировку, но зато 
может определить когда она неверна*/
20 октября 2009, 19:02

Использование счетчика liveinternet.ru на wap сайте

<?php
/**
 * Использование счетчика liveinternet.ru на wap сайте
 * автор: Nc_Soft
 * 28.09.09
 */

/*
Думаю все встречали этот счетчик хоть раз в вебе.
При уёбищном дизайне он даёт отличные статистические данные по сайту, но
из-за ява скрипта в коде счетчика его использование на wap сайте не предоставляется возможным.
Давайте поправим эту оплошность

Оригинальный код счетчика можно получить на 
http://www.liveinternet.ru/code?nick=ВАШ_САЙТ

<!--LiveInternet counter-->
          <script type="text/javascript"><!--
document.write("<a href='http://www.liveinternet.ru/click' "+
"target=_blank><img src='http://counter.yadro.ru/hit?t52.5;r"+
escape(document.referrer)+((typeof(screen)=="undefined")?"":
";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?
screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+
";"+Math.random()+
"' alt='' title='LiveInternet: показано число просмотров и"+
" посетителей за 24 часа' "+
"border=0 width=88 height=31><\/a>")//--></script>
          <!--/LiveInternet-->

Теперь реализуем это всё без ява скрипта и наслаждаемся результатом
*/

echo '<a href="http://www.liveinternet.ru/click">
<img src="http://counter.yadro.ru/hit?t25.10;r'.urlencode($_SERVER['HTTP_REFERER']).';uhttp%3A//'.urlencode($_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']).';0.'.rand(12345, 893855).'" alt="" /></a>';

//примечательно то, что нигде не фигурирует имя домена явно
28 сентября 2009, 00:10

Защита от sql инъекций

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

/*
Почему-то разработчики PHP не сделали функцию для работы с бд,
которая принимает запросы с параметрами.
Это сильно бы помогло в безопасности.
*/

//эта функция экранирует параметры
function qw() {
	$args = func_get_args();

	$query = array_shift($args);
	$args = array_map('mysql_real_escape_string', $args);
	array_unshift($args, $query);
	$query = call_user_func_array('sprintf', $args);
	
	if (!$query) die('неверный запрос');
	
	return mysql_query($query);
}

//пример использования
$q = qw("SELECT * FROM tbl WHERE login='%s' AND pass='%s' ", "лог'ин", "пар'оль");
//в этом запросе все кавычки будут экранированы, инъекция невозможна

/*вместо %s в функцию подставляется параметр, обработанный через mysql_real_escape_string
поэтому нет никакой необходимости предварительно обрабатывать данные , можно писать сразу
qw("SELECT FROM tbl WHERE id='%s' ", $_GET['id']);
Главное не забыть поместить %s в кавычки.
*/
15 сентября 2009, 20:13

Sitemap генератор для мобильных устройств при помощи simplexml

<?php
/**
 * Sitemap генератор для мобильных устройств при помощи simplexml
 * автор: Nc_Soft
 * 09.09.09
 */

/*
Пару слов зачем это нужно:
Позволяет ускорить индексацию поисковиками труднодоступных мест,
сообщая конкретные урл страниц.

http://www.google.com/support/webmasters/bin/answer.py?hl=ru&answer=34627
http://www.google.com/support/webmasters/bin/topic.py?topic=8493
*/

/*
Перейдем к реализации:
К примеру, имеется массив из 10 элементов, эмулирующий ид из бд
array(1, 2, ... , 10)
*/
$ids = range(1, 10);

//пусть каждому элементу соответствуем страница на сайте http://site.ru/$id.html

//собственно, генерация
$sitemap = simplexml_load_string('<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0"></urlset>');

foreach ($ids as $id) {
	$url = $sitemap->addChild('url');
	$url->loc = "http://site.ru/$id.html";
	$url->addChild('mobile', null, 'http://www.google.com/schemas/sitemap-mobile/1.0');
}

header('Content-type: text/xml; charset=utf-8');
echo $sitemap->asXML();

/*
Sitemap готов, сохраняете его как sitemap.php и добавляете в гугл как тут сказано
http://www.google.com/support/webmasters/bin/answer.py?answer=40348

также вы можете добавить доп.инфу в sitemap для каждой страницы
http://www.google.com/support/webmasters/bin/answer.py?answer=71936
*/
9 сентября 2009, 10:05

Мультипоточное скачивание через CURL

<?php
/**
 * Мультипоточное скачивание через CURL
 * 01.09.09
 * автор: Nc_Soft 
 */

//В php5 можно скачивать данные в несколько потоков

//инициализация
$ch1 = curl_init();
$ch2 = curl_init();

//адреса страниц (файлов) и опции
curl_setopt($ch1, CURLOPT_URL, 'kmx.ru');
curl_setopt($ch1, CURLOPT_HEADER, 1);
curl_setopt($ch2, CURLOPT_URL, 'wen.ru');
curl_setopt($ch2, CURLOPT_HEADER, 1);

//мульти загрузка
$mh = curl_multi_init();

//добавляем ресурсы в мультизагрузку
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);

//число запущенных загрузок
$running=null;

//грузим!
do {
	curl_multi_exec($mh, $running);
} while ($running > 0);


//освобождаем ресурсы и память
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);

?>
1 сентября 2009, 12:10

Получение представления таблицы mysql

<?php
/**
 * Получение представления таблицы mysql
 * автор: Nc_Soft
 * 31.08.09
 */

$q = mysql_query("SELECT * FROM tbl");

$thead = false;
echo '<table border="1">';
while (false !== $res=mysql_fetch_assoc($q)) {
	if ($thead === false) {
		$thead = true;
		echo '<tr>';
		foreach (array_keys($res) as $v) {
			echo '<td>'.$v.'</td>';
		}
		echo '</tr>';
	}

	echo '<tr>';
	foreach ($res as $ceil) {
		echo '<td>'.$ceil.'</td>';
	}
	echo '</tr>';
}
echo '</table>';
31 августа 2009, 15:19