1+7=7?

<?php
echo (int) ((0.1 + 0.7) * 10); //7

/*никогда не приводите неизвестную дробь к целому!
http://ru.php.net/manual/ru/language.types.integer.php
*/
?>
12 февраля 2009, 01:26

Логарифмическое облако тегов

<?php
/**
 * Логарифмическое облако тегов
 * автор: Nc_Soft
 * 22.01.09
 */

/*
Допустим, имеем теги и частоту их встречаемости
тег1 5
тег2 6
тег3 9
тег4 2
тег5 8
тег6 13
тег7 1
тег8 16
....
*/

//эти данные обычно берутся из бд, тут же я проимитирую их массивом
$tags=array(
'тег1'=> 5,
'тег2'=> 6,
'тег3'=> 9,
'тег4'=> 2,
'тег5'=> 8,
'тег6'=> 13,
'тег7'=> 1,
'тег8'=> 16,
);

$minSize=10; //минимальный размер шрифта
$maxSize=26; //максимальный размер шрифта

$minWeight=min($tags); //минимальный вес тега
$maxWeight=max($tags); //максимальный вес тега

$tegi=array();

//вычислим размер шрифта тегов
foreach ($tags as $tag=>$tagWeight) {
	
	//шрифт по логарифмическому закону
	$font= floor( (log($tagWeight + 1) - log($minWeight + 1)) / (log($maxWeight + 1) - log($minWeight + 1)) * ($maxSize - $minSize) + $minSize );
	
	//добавим в массив
	$tegi[]='<a href="" style="font-size:'.$font.'px">'.$tag.'</a>';
}

//теперрь перетасуем и выведем
shuffle($tegi);

echo implode('<br />',$tegi);

/*
кому интресно что получилось могут запустить :)
*/

?>
22 января 2009, 09:06

Проверка email

<?php
/**
 * Проверка email
 * автор: Nc_Soft
 * 19.01.09
 */

//все еще изобретаете велосипеды?
//тогда мы идем к вам :)

if (filter_var('example@example.com', FILTER_VALIDATE_EMAIL)) {
	echo 'емаил верный<br />';
}

if (filter_var('_example@example.com', FILTER_VALIDATE_EMAIL)) {
	echo 'емаил неверный<br />';
}

?>
19 января 2009, 19:40

Переадресация с задержкой

<?php
/**
* Переадресация с задержкой
* автор: Nc_Soft
* 15.01.09
*/

header('Refresh: 3; URL=http://example.com');
echo 'Через 3 сек. вы будете перенаправлены на новую страницу.';
exit;
?>
15 января 2009, 14:38

Определение знака зодиака

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

//массив для сравнений
$zodiak=array(
'Oven'=>'Овен',
'Taurus'=>'Телец',
'Gemini'=>'Близнецы',
'Cancer'=>'Рак',
'Leo'=>'Лев',
'Virgo'=>'Дева',
'Libra'=>'Весы',
'Scorpion'=>'Скорпион',
'Sagittarius'=>'Стрелец',
'Capricorn'=>'Козерог',
'Aquarius'=>'Водолей',
'Fish'=>'Рыбы'
);

//функция опеределения
function zodiak($d,$m) {

	$d=sprintf('%02d',$d);
	$m=sprintf('%02d',$m);

	if (($m=='03' AND $d>20) OR ($m=='04' AND $d<21)) return 'Oven';
	if (($m=='04' AND $d>20) OR ($m=='05' AND $d<22)) return 'Taurus';
	if (($m=='05' AND $d>21) OR ($m=='06' AND $d<22)) return 'Gemini';
	if (($m=='06' AND $d>21) OR ($m=='07' AND $d<23)) return 'Cancer';
	if (($m=='07' AND $d>22) OR ($m=='08' AND $d<24)) return 'Leo';
	if (($m=='08' AND $d>23) OR ($m=='09' AND $d<24)) return 'Virgo';
	if (($m=='09' AND $d>23) OR ($m=='10' AND $d<24)) return 'Libra';
	if (($m=='10' AND $d>23) OR ($m=='11' AND $d<23)) return 'Scorpion';
	if (($m=='11' AND $d>22) OR ($m=='12' AND $d<22)) return 'Sagittarius';
	if (($m=='12' AND $d>21) OR ($m=='01' AND $d<19)) return 'Capricorn';
	if (($m=='01' AND $d>20) OR ($m=='02' AND $d<19)) return 'Aquarius';
	if (($m=='02' AND $d>18) OR ($m=='03' AND $d<21)) return 'Fish';

	return null;
}

//тестирование (пример для 3 декабря)
echo $zodiak[zodiak(3,12)]; //Стрелец

?>
12 января 2009, 08:26

Определениие возраста по дате рождения (mysql)

<?php
/**
 * Определениие возраста по дате рождения (mysql)
 * автор: Nc_Soft
 * 11.01.09 
 */

//Этот вариант дал протечку  на дате 1982-02-24 на 2 марта 2009 он выводит что челу 26 лет

/* поле даты должно иметь в базе тип DATE !! 
пример для даты произвольной даты 1984-08-25 */
echo mysql_result(
mysql_query("
SELECT DATE_FORMAT(DATE_SUB(FROM_DAYS(TO_DAYS(NOW()) - TO_DAYS('1984-08-25')), INTERVAL 1 MONTH ), '%y') as age
"
)
,0,0);

/*
Поэтому юзаем вариант Ририса
SELECT (YEAR(CURRENT_DATE) - YEAR(`birth`)) - (DAYOFYEAR(CURRENT_DATE) < DAYOFYEAR(`birth`)) as `age`
*/

?>
11 января 2009, 10:36

Постраничная навигация с ООП

<?php
/**
 * Постраничная навигация с ООП
 * автор: Nc_SOft
 * 08.01.09
 */


//класс навигатор представлен ниже, его лучше сохранить в отдельном файле
//пример использования: 1.навигация в массиве

//это массив 1,2,3,..,100
$arr=range(1,100);

//создаем навигатор
$n=new Navigator('',5);

//всего элементов
$all=count($arr);

//теперь возьмем 5 элементов из массива при помощи SPL
$larr=new LimitIterator(new ArrayIterator($arr), $n->start(), $n->pnumber);

//выводим элементы
echo '<div>';
foreach ($larr as $k=>$v) {
	if ($k) echo '<br />';
	echo $v;
}
echo '</div>';

//и печатаем навигацию
echo $n->navi($all);


//теперь пример с БД
//создаем навигатор
$n=new Navigator('',5);

//делаем запрос(например, к таблице юзеров id|login)
$q=mysql_query("SELECT SQL_CALC_FOUND_ROWS id,login FROM users ORDER BY id LIMIT {$n->start()}, $n->pnumber ");
$all=mysql_result(mysql_query("SELECT FOUND_ROWS()"),0,0);

while (false!==($res=mysql_fetch_assoc($q))) {
	print_r($res);
}

//навигация
echo $n->navi($all);




//а вот и сам навигатор, если есть идеи как его улучшить пишите
class Navigator {
	/**
	 * конструктор
	 *
	 */
	function __construct($script,$pnumber,$query='') {
		$this->script=$script;

		//если не задано имя скрипта, то используем текущее
		if (empty($script)) {
			$this->script=$_SERVER['SCRIPT_NAME'];
		}

		//элементов на страницу
		$this->pnumber=$pnumber;

		$this->query='';
		$this->or_query=$query;

		//если задана строка параметров
		if (is_array($query)) {
			foreach ($query as $k=>$v) {
				$this->query.='&'.$k.'='.urlencode($v);
			}
		}

		//обработка текущего номера страницы
		$this->page=isset($_GET['page']) ? (int)$_GET['page'] : 1;
	}

	/**
	 * Инициализация навигатора, вычесление стартовой позиции
	 */
	function start() {

		//вычисление стартовой позиции
		$this->start = $this->page * $this->pnumber - $this->pnumber;

		//обработка левых номеров
		if ($this->page < 1) {
			$this->page=1;
			$this->start=0;
		}

		return $this->start;
	}

	/**
	 * Печать навигатора
	 */
	function navi($all,$input=0) {

		//всего элементов
		$this->all=$all;

		//число страниц
		$this->num_pages=ceil($this->all/$this->pnumber);

		//если страниц более 5, то выводим форму
		if ($this->num_pages > 5) $input=1;

		//проверка корректности
		if ($this->page > $this->num_pages || $this->page < 1) {
			$this->page=1;
			$this->start=0;
		}

		//не печатаем навигатор, если всего одна страница
		if ($this->num_pages<2)
		return '';

		$buff='<div class="navi">';

		//блок вперед
		if ($this->page>1)
		$buff.='<a href="'.$this->script.'?page='.($this->page-1).$this->query.'"><</a>';
		else
		$buff.='<';

		//блок ссылок
		for($pr = '', $i =1; $i <= $this->num_pages; $i++) {
			$buff.=
			$pr=(($i == 1 || $i == $this->num_pages || abs($i-$this->page) < 2) ? ($i == $this->page ? " [$i] " : ' <a href="'.$this->script.'?page='.$i.$this->query.'">'.$i.'</a> ') : (($pr == ' ... ' || $pr == '')? '' : ' ... '));
		}

		//блок назад
		if ($this->page<$this->num_pages)
		$buff.='<a href="'.$this->script.'?page='.($this->page+1).$this->query.'">></a>';
		else
		$buff.='>';

		//печатаем форму с полем ввода (можно это убрать отсюда если не требуется)
		if ($input) {
			$buff.='<form style="margin:0" action="'.$this->script.'" method="get"><p style="margin:0">';

			$buff.='<input size="2" name="page" value="'.$this->page.'"/>';

			if (!empty($this->query)) {
				foreach ($this->or_query as $name=>$value) {
					$buff.='<input type="hidden" name="'.$name.'" value="'.htmlspecialchars($value).'" />';
				}
			}

			$buff.='<input type="submit" value=">>"/></p></form>';
		}

		$buff.='</div>';

		return $buff;
	}
}
8 января 2009, 19:01

Установка временной зоны в Mysql

<?php
/**
 * Установка временной зоны в Mysql
 * автор: Nc_Soft
 * 08.01.09
 */

/*если putenv('TZ=Europe/Moscow'); не помогает перевести время в Mysql, 
то можно попробовать вот такой способ
*/
mysql_query("SET LOCAL time_zone='+03:00'");

/*
тут время задается по Гринвичу, этот запрос надо сделать при коннекте к бд
*/
?>
8 января 2009, 18:15

Установка временной зоны

<?php
/**
 * Установка временной зоны
 * автор: Nc_Soft
 * 08.01.09
 */

/*очень часто приходится видеть такое
echo date('H:i:s'+time()*3600);
есть способ проще!
*/
putenv('TZ=Europe/Moscow');

/*
узнать свою зону можно через поисковик, нагуглилось за 5 секунд
http://www.cms4site.ru/ru-webmodules-datetime-zonetable.html
*/
?>
8 января 2009, 18:12

Создание символической ссылки на файл

<?php
/**
 * Создание символической ссылки на файл
 * автор: Nc_Soft
 * 03.01.09
 */

/*
Имеется некоторая защищенная директория (deny from all), в которой лежат файлы
1.mp3
2.mp3
3.mp3 итп
Задача выдать эти файлы с произвольным именем юзеру по запросу
*/

//защищенная директория
$private_dir=$_SERVER['DOCUMENT_ROOT'].'/private';

//создадим доступную директорию public с правами 777
$public_dir=$_SERVER['DOCUMENT_ROOT'].'/public';

/*в директорию public будем класть символические ссылки.
Обращаю внимание, что символические ссылки ничего не весят.
Допустим, мы хотим выдать ссылку на файл /private/1.mp3 в виде
/public/mega_hit_track.mp3
*/

//создаем символическую ссылку
if (symlink($private_dir.'/1.mp3', $public_dir.'/mega_hit_track.mp3')) {
	//выдаем ссылку юзеру
	echo '<a href="http://'.$_SERVER['HTTP_HOST'].'public/mega_hit_track.mp3">скачать</a>';
}
else {
	echo 'ошибка генерации ссылки';
}

/*в папке public создалась символическая ссылка 
mega_hit_track.mp3
обращение http://'.$_SERVER['HTTP_HOST'].'public/mega_hit_track.mp3
приведет к скачиванию статичного файла /private/1.mp3 из папки 

Преимущества символических ссылок:
-ссылки можно генерировать на лету
-можно сделать несколько разных ссылок на один и тот же файл
-с символическими ссылками можно работать как с файлами и каталогами (удаление/перемешение/переименование)

Недостатки:
-работает только в Linux
*/

?>
3 января 2009, 04:38

Определение запущенных процессов

<?php
/**
 * Определение запущенных процессов
 * автор: Nc_Soft
 * 03.01.09
 */

/*
Очень часто видео на сервере конвертируют по крону (потому что это очень ресурсоемкая процедура).
Для этого возникает необходимость узнать сколько ffmpeg'ов запущено.
Если запущено более 1 экземпляра конвертацию лучше отложить до следующего запуска
*/

//выполним такую команду и результат пихнем в $pslist
exec("ps aux | grep ffmpeg", $pslist);

/*строка, которая нас интересует выглядит как-то так
user   74080 95.1  0.6 32732 21788  ??  R     2:09AM   0:20.81 /usr/bin/ffmpeg
*/


//осталось только перебрать массив
foreach ($pslist as $r) {
	$v=preg_split('|\s+|', $r);
	if ($v[10] == '/usr/bin/ffmpeg') die('ffmpeg уже запущен, выходим');
}

//аналогично можно поступить с другими процессами, например с lame

?>
3 января 2009, 04:06

Использование preg_replace_callback в методе класса

<?php
/**
 * Использование preg_replace_callback в методе класса
 * автор: Nc_Soft
 * 03.01.09
 */

/*
Предположим, что надо сделать замену для смайлов
смайлы будут иметь вид <ЧИСЛО> и заменять это будем на <img src="/smile/ЧИСЛО.jpg" alt="" />
доп условия:
	-число замен не более 3
	-число в смайле должно соответствовать некоторому условию (в примере это диаппазон от 1 до 15)
*/

class Smile {

	//учитываем число замен
	private $smiles=0;

	//функция печати смайлов
	 function print_smiles($text) {
		return preg_replace_callback('|<(\d+)>|',array($this,'scb'),$text);
	}

	//функция обратного вызова для регулярки
	private function scb($v) {
		if ($this->smiles<3 && $v[1]>=1 && $v[1]<=15) {
			$this->smiles++;
			return '<img src="/smile/'.$v[1].'.jpg" alt="" />';
		}
		return $v[0];
	}
}

//пример
$s=new Smile();
echo $s->print_smiles('<1> <23><3><5><4>');

?>
3 января 2009, 03:56

Вывод файлов определенного типа при помощи SPL

<?php
/**
 * Вывод файлов определенного типа при помощи SPL
 * автор: Nc_Soft
 * 10.12.08
 */

/*напишем фильтр
для этого надо расширить FilterIterator, реализовав метод
accept()
*/
class F_FileIterator extends FilterIterator
{
	private $ext;
	private $it;

	function __construct(DirectoryIterator $it,$ext)
	{
		parent::__construct($it);
		$this->it=$it;
		$this->ext=$ext;
	}

	function accept()
	{
		return (pathinfo($this->current(),PATHINFO_EXTENSION)==$this->ext) ? true : false;
	}
}

//а теперь выведем из текущей директории только php файлы
$d=new F_FileIterator(new DirectoryIterator('./'), 'php');

foreach ($d as $v)
{
	echo "$v<br />\n";
}
?>
10 декабря 2008, 12:08

Подключение по https через CURL с посылкой сертификата

<?php
/**
 * Подкдючение по https через CURL с посылкой сертификата
 * автор: Nc_Soft
 * 19.11.08
 */

//!необходимо скачать сертификат ( в примере это WebMoneyCA.crt )

$ch=curl_init('https://w3s.webmoney.ru/asp/XMLInvoice.asp');
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
curl_setopt($ch, CURLOPT_CAINFO, 'WebMoneyCA.crt');
echo curl_exec($ch);

?>
19 ноября 2008, 20:38

Подключение по https через CURL

<?php
/**
 * Подкдючение по https через CURL
 * автор: Nc_Soft
 * 19.11.08
 */

//чтобы просто получить страницу!
$ch=curl_init('https://www.icq.com/register/');
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
echo curl_exec($ch);

?>
19 ноября 2008, 20:34

Удаленное определение степени gzip сжатия

<?php 
/** 
 * Удаленное определение степени gzip сжатия 
 * автор: Nc_Soft 
 * 15.11.08 
 */ 

//экзаменуемая страница 
$url='http://example.com'; 
$ch=curl_init($url); 
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); 
$bez=curl_exec($ch); 
curl_close($ch); 
$bez=strlen( $bez ); 

$ch=curl_init($url); 
curl_setopt($ch,CURLOPT_HTTPHEADER,array('Accept-Encoding: gzip, deflate')); 
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); 
$s=curl_exec($ch); 
curl_close($ch); 
$s=strlen( $s ); 

echo (1-$s/$bez)*100; 
echo '%'; 

?>
15 ноября 2008, 02:53

Переменная в шаблоне preg_replace

<?php
/**
 * Переменная в шаблоне preg_replace
 * автор: Nc_Soft
 * 14.11.08
 */

/*
источник: http://www.umi-cms.ru/company/vacansy/developer_php5/
задача:
Изменяя только переменные $foo и $bar выполнить функцию phpinfo в preg_replace.
*/
$foo = "the";
$bar = "THE";

$zoo = <<< END
Once upon tHe time were thE three bears...
END;

echo preg_replace("/{$foo}/im", $bar, $zoo);

/*
решение взято с http://kay.habrahabr.ru/blog/44590/
*/
$foo = "the/ie\0"; 
$bar = "phpinfo()";

echo preg_replace("/{$foo}/im", $bar, $zoo);

/*
ошибка в отсутствии фильтрации шаблона,
исправленный вариант:
*/
$foo = preg_quote($foo, '/');
echo preg_replace("/{$foo}/im", $bar, $zoo);

?>
14 ноября 2008, 14:59

Проверка хоста

<?php
/**
 * Проверка хоста
 * автор: Nc_Soft
 * 12.11.08
 */

//используется функция checkdnsrr, если ее нет (винда), то юзаем виндовскую nslookup
if(!function_exists('checkdnsrr')){
	function checkdnsrr($host, $type=''){
		if(!empty($host)){
			$type = (empty($type)) ? 'MX' :  $type;
			exec('nslookup -type='.$type.' '.escapeshellcmd($host), $result);
			$it = new ArrayIterator($result);
			foreach(new RegexIterator($it, '~^'.$host.'~', RegexIterator::GET_MATCH) as $result){
				if($result){
					return true;
				}
			}
		}
		return false;
	}
}

//проверим адрес
$url='http://wen.ru/forum';

if (checkdnsrr(parse_url($url,PHP_URL_HOST)))
{
	echo 'хост верен';
}
else 
{
	echo 'хост неверен';
}

//проверим кривой адрес
$url='http://gfghhrwen.ru/forum';

if (checkdnsrr(parse_url($url,PHP_URL_HOST)))
{
	echo 'хост верен';
}
else 
{
	echo 'хост неверен';
}

/*
все материалы на
http://php.net/checkdnsrr
*/
?>
12 ноября 2008, 22:22

Установка часового пояса

<?php
/**
 * Установка часового пояса
 * автор: Nc_Soft
 * 04.11.08
 */

/*
Знакома ситуация, когда часы у хостера работают в другом часовом поясе?
Конечно, можно править время во всех скриптах, аля time()+n*3600
но есть способ проще!
*/ 

//например, для Москвы добавьте эту строчку
putenv('TZ=Europe/Moscow');

//проверка
echo date('r');

/*
Посмотреть все зоны можно, например, тут http://www.timezoneconverter.com/
Конечно, это может сработать не на всех хостингах...
*/
4 ноября 2008, 15:35

Применение ON DUPLICATE KEY

<?php
/**
 * Применение ON DUPLICATE KEY
 * автор: Nc_Soft
 * 01.11.08
 */

/*
Допустим, у нас имеется таблица online юзеров, вот такая:
id | time
id - первичный или укальный ключ
нам надо обновлять время последнего пребывания юзера на сайте, либо добавить запись  в таблицу
*/

//Как это обычно делают в 2 запроса (НЕПРАВИЛЬНО!)
if (false===mysql_query("INSERT INTO online SET id='{$_SESSION['id']}', time=NOW() "))
{
	//если предыдущий запрос не прошел, то запись в таблице с ключом id уже есть, обновляем
	mysql_query("UPDATE online SET time=NOW() WHERE id='{$_SESSION['id']}' ");
}

//а теперь покажем как сделать правильно
mysql_query("INSERT INTO online SET id='{$_SESSION['id']}', time=NOW() ON DUPLICATE KEY UPDATE time=NOW() ");

/*
Как видите, применение ON DUPLICATE KEY позволяет уменьшить число запросов к бд
*/
1 ноября 2008, 13:14