мая 24 2010

Функция удаления дублей в массиве

Автор: admin | В рубриках: Новости

Функция удаляющая произвольный элемент или список элементов в массиве (например удаление пустых элементов)

function array_clean( $array, $needle = null ) {
  if(!is_array($needle)) $needle = array($needle);
  return array_diff( $array, $needle );
}

Возьмем массив

$array = array('first', '', 'second', 'first', '', 'third', '', 'second', 'third');

Удалим в нем все пустые элементы:

$result = array_clean($array);

Либо список элементов (пустые, second и third):

$result = array_clean($array, array(null, 'second', 'third'));

Результат:

Array
(
[0] => first
[3] => first
)

Отзывов пока нет

Фев 04 2010

Время выполнения скрипта PHP

Автор: admin | В рубриках: Новости

Каждый скрипт нуждается в отладке, а одним из параметров качественной работы является быстрая скорость работы той или иной функции или ПО в принципе.
PHP не предоставляет стандартных способов получения такой информации, соответственно приходится прибегать к модификациям кода. Скорость выполнения можно определить получив значения времени в момент запуска какого-либо участка кода и в момент окончания его выпонения. Максимально точно определить текущее время можно командой microtime() которая возвращает текущее время в unix формате с миллисекундами.
Результат данного кода:

<?php
echo microtime();
?>

будет примерно следующим:
0.23425000 1265223276
где первая часть – миллисекунды, а вторая метка времени в unix формате.
чтобы получить текущее время с миллисекундами эти значения необходимо сложить.
Разбить их можно с помощью функции explode.
Итого точное текущее время мы получим выполнив:

$time = explode(' ', microtime());
$time = $time[1] + $time[0];

Теперь можем упростить эту задачу используя функцию array_sum()

$time = array_sum(explode(' ', microtime()));

Таким образом мы получили метку времени запуска. Метка конца выполнения получается аналогичным образом, далее вычетаем метку запуска из метки остановки и получаем разницу во времени которая и является временем выполнения участка кода.

$start = array_sum(explode(' ', microtime()));
/* code */
sleep(1); // Задержка в 1 секунду
printf ("%f sec.", (array_sum(explode(' ', microtime())) - $start));

Результат: 1.000069 sec.
Без кода между вычислениями можно определить погрешность в расчете за счет внедрения данного кода. В моем случае она составляет не более 0.0001 секунды. Данный момент в большей степени зависит от конфигурации системы и железа.

Примечание:
В версии PHP 5.0.0 у функции microtime() появился необзательный параметр (bool)get_as_float, при указании которого функция вернет действительное число. В данном случае можно сократить код за счет избавления от “ненужных” функций explode() и array_sum()

//ДАННЫЙ МЕТОД ПРИМЕНИМ К PHP ВЕРСИЕЙ НЕ НИЖЕ 5.0.0
$start = microtime(1);
/* code */
sleep(1); // Задержка в 1 секунду
printf ("%f sec.", microtime(1) - $start);

К слову работает этот способ в разы быстрее, за счет чего более предпочтителен.

Отзывов пока нет

Дек 08 2009

Редиректы HTML, PHP, Javascript

Автор: admin | В рубриках: HTML, JS Скрипты, PHP скрипты

HTML

<meta http-equiv="refresh" content="15; url=http://php-developer.ru/">

где:
15 – задержка перед редиректом в секундах.
http://php-developer.ru/ – страница на которую попадем.
Для перенаправления без задержки – укажите 0 сек.

PHP

header("Location: http://php-developer.ru/");

Моментальный редирект без загрузки текущей страницы. Обратите внимание что данный заголовок должен быть отправлен ДО вывода какого либо текста, иначе – получите ошибку.

PHP-Редирект с задержкой:

header("Refresh:15;URL=http://php-developer.ru/");

где:
15 – задержка перед редиректом в секундах.
http://php-developer.ru/ – страница на которую производится перенаправление.
В данном случае сохраняется требование того, что перед отправкой данного заголовка не должно быть вывода какого либо текста, однако в отличии от предыдущего примера – страница успешно загрузится.

Редирект на уровне веб-сервера.

Стандартная задача веб-мастеров – запретить доступ сайта к домену с “www” и организовать перенаправление на адрес без него. Или наоборот. Для расматриваемого варианта необходимо создать в корне сайта файл .htaccess и разместить в нем следущее правило:

DirectoryIndex index.php
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.php-developer.ru$ [NC]
RewriteRule ^(.*)$ http://php-developer.ru/$1 [R=301,L]

Где:
index.php – index файл вашего сайта
www.php-developer.ru – домен с которого производится перенаправление
http://php-developer.ru/ – домен на который производится редирект
301 – код “ошибки” сопровождающий редирект. (в данном случае 301 ошибка – Ресурс перемещен навсегда. Например 302 ошибка – ресурс перемещен временно.)

JavaScript редирект

Данный js-код при выполнении произведет немедленную переадресацию на сайт http://php-developer.ru/

document.location.href = "http://php-developer.ru/"

аналогичным образом можно изменять страницу фрейма, всплывающего окна и т.п. Достаточно просто обратиться к объекту и указать для него location.href=”url”

Отзывов пока нет

Окт 30 2009

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

Автор: admin | В рубриках: MySQL, PHP скрипты

Вопросы о реализации постраничной навигации всплывают давольно часто, и не только среди новичков. Новички ищут любые “рабочие” способы, а профессионалы

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

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

исследования сегодня будет параметр SQL_CALC_FOUND_ROWS оператора SELECT. Данный параметр появился в MySQL начиная с версии 4.0.0, суть его работы

заключается в том, что при его использовании MySQL проведет “подсчет” и запись количества записей по указанному запросу, результат которого можно будет позже

получить через параметр FOUND_ROWS(), того же оператора SELECT.
Простейший пример его работы ниже:

SELECT SQL_CALC_FOUND_ROWS * FROM `table`

Если предположить, что в таблице table находится 1050 записей, то результат оператора SELECT с параметром FOUND_ROWS():

SELECT FOUND_ROWS()

будет следующий: Array ( [FOUND_ROWS()] => 1050 )
таким образом, выполняя любой SELECT запрос, с данным параметром, мы автоматически получаем возможность “отслеживать” количество записей удовлетворяющим

данному запросу, что несомненно можно использовать для реализации нашей задачи. Еще один пример. Допустим, у нас есть таблица catalogue, из которой

необходимо получать данные разбивая их на страницы. Причем обрабатывать нужно только те записи которые удовлетворяют каким либо условиям. например WHERE

`price` < 1000.00. Итого получаем следущий запрос:

SELECT * FROM `catalogue` WHERE `price` < 1000.00

Для того чтобы ограничить вывод записей в рамках одной страницы необходисо указать параметр LIMIT первое значение которого будет указывать на номер записи с

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

параметр SQL_CALC_FOUND_ROWS.
Итого понимаем, что для этого нам необходим примерно следующий запрос:

SELECT SQL_CALC_FOUND_ROWS * FROM `catalogue` WHERE `price` < 1000.00 LIMIT 1, 10

Который выведет 10 записей начиная с первой из таблицы catalogue, где цена товара меньше 1000.00. Учитывая, что все программисты чертовски ленивые ;) мы

перекладываем ответственность за обработку стандарных запросов на свою функцию, чтобы мы могли не отвлекаясь на все "дополнительные параметры" использовать в

работе только оригинальные запросы. Соответственно перво-наперво нам необходимо получить количество записей по исходному запросу, для чего используем способ

описанный выше. Преобразуем SELECT запрос, и получаем количество записей:

$result = mysql_query('SELECT SQL_CALC_FOUND_ROWS' . substr($sql, 6));
$result = mysql_fetch_assoc(mysql_query('SELECT FOUND_ROWS()'));

Первая строка добавляет к оператору SELECT параметр SQL_CALC_FOUND_ROWS в исходной SQL строке, а вторая выполняет SQL запрос на получение количества записей.
Далее нам необходимо определить количество записей выводимых на одной странице и собственно номер текущей страницы. Для этого введем переменную $onPage со

значением 10 (10 строк на страницу), и переменную $currentPage значение которой будем брать из GET параметра "page". Подсчитаем общее количество страниц и

обработаем значение $currentPage.

$totalPages = intval(($result['FOUND_ROWS()'] - 1) / $onPage) + 1;
$currentPage = empty($currentPage) || $currentPage < 0 ? 1 : intval($currentPage);
if ($currentPage > $totalPages) $currentPage = $totalPages;

Далее нам осталось только посчитать номер записи с которой нужно начинать выборку исходя из текущей страницы, и выполнить данный запрос:

$start = $currentPage * $onPage - $onPage;
$result = db::query($sql . ' LIMIT '.$start.', '.$onPage);

В результате мы получаем ресурс в переменной $result, который уже можем обрабатывать PHP, например, через mysqli_fetch_assoc()
Чтобы еще больше упростить задачу оформим всё вышеизложенное в виде функции:

function paging ($sql, $currentPage = 1, $onPage = 10) {
  $result = mysql_query('SELECT SQL_CALC_FOUND_ROWS' . substr($sql, 6));
  $result = mysql_fetch_assoc(mysql_query('SELECT FOUND_ROWS()'));
  $totalPages = intval(($result['FOUND_ROWS()'] - 1) / $onPage) + 1;
  $currentPage = empty($currentPage) || $currentPage < 0 ? 1 : intval($currentPage);
  if ($currentPage > $totalPages) $currentPage = $totalPages;
  $start = $currentPage * $onPage - $onPage;
  $result = mysql_query($sql . ' LIMIT '.$start.', '.$onPage);
  return $result;
}

В полевых условиях используется эта функция вместо функции mysql_query.

$curPage = !isset($_GET['page']) || empty($_GET['page']) ? 1 : $_GET['page'];
$result = paging ($sql, $curPage);
while ($row = mysql_fetch_assoc($result)) {
 /* ... */
}

Отзывов (7)

Окт 24 2009

Генерация «превью» текста, PHP

Автор: admin | В рубриках: PHP скрипты

Возникла необходимость генерации “краткого” текста таким образом, чтобы в общем, списке под каждым заголовком были первые строки статьи. Статью же целиком можно прочитать по клику на ссылку “подробнее”. Казалось бы, чего сложного, обрезается текст до “нужной” длины функцией substr и готово. Но в такой реализации есть неприятный момент, а именно – “нужная” длина может окончиться на середине слова, и вместо слова, например, “немедленно” на выходе последним словом получим “немедл”… В теории необходимо получить сначала текст необходимой длины, а затем, добавляя к результату по одной букве до тех пор, пока не встретим его конец, то есть пробел. Де-факто функция реализующая такой метод представлена ниже:

function preview_desc ( $str, $length = 100 ) {
  $result = substr ( stripslashes( $str ), 0, $length );
  while( true ) {
    if( $tmp = substr ( stripslashes( $str ), $length, 1 ) ) {
      if ( $tmp == ' ' ) break;
      $result .= $tmp;
    } else break;
    $length++;
  }
  return $result;
}

Параметров у функции два:
$str (string) – Собственно исходная строка
$length (int) – Длина текста после первичного укорачивания (на практике будет немного больше за счет добавляемых символов). Необязательный параметр – по умолчанию 100 символов.

UPDATE
По просьбам читателей вариант без цикла :)

function preview_desc ( $str, $length = 100 ) {
  $str =  stripslashes( $str ) . ' ';
  $result = substr ( $str, 0, $length );
  $space_pos = strpos( $str, ' ', $length );
  $result .= substr ( $str, $length, $space_pos - $length );
  return $result;
}

Входные параметры те же самые, но меняется принцип “добавления” куска текста от сотого символа и до пробела. Добавление этого куска получается путём поиска в оставшемся тексте номера позиции символа пробела и вырезанием куска от $length до $space_pos.

Написал этот код и понял, что можно пойти еще дальше. как минимум в этом коде есть одно бесполезное действие, длиной в две строчки.

function preview_desc ( $str, $length = 100 ) {
  $str =  stripslashes( $str ) . ' ';
  $space_pos = strpos( $str, ' ', $length );
  $result = substr ( $str, 0, $space_pos );
  return $result;
}

Так вроде лучше :)

Отзывов (2)

Сен 18 2009

Определение города по IP адресу на PHP

Автор: admin | В рубриках: PHP скрипты

Рано или поздно каждый из нас сталкивается с вопросом определения города посетителя. Будь то в целях формирования подробной статистики и еще чего. Да что там посетителя – любого IP, и как раз для этих целей существуют разные базы IP адресов, некоторые из них (как в нашей функции) очень удобно предоставляют данные через API.

Итак, встречайте: Скрипт определения города на PHP.

function geo_info($ip)
  {
    $xml = "<ipquery><fields><city/></fields><ip-list>"
         . "<ip>".$ip."</ip></ip-list></ipquery>";
    $ch = curl_init("http://194.85.91.253:8090/geo/geo.html");
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
    $result = curl_exec($ch);
    if(curl_errno($ch) != 0)
      die("curl_errno(".curl_errno($ch)."), curl_error(".curl_error($ch).")");
    curl_close($ch);
    if (strpos($result, '<message>Not found</message>') !== false)
      return false;
    preg_match("/<city>(.*)<\/city>/", $result, $city);
    return $city[1];
  }

Вот именно! Благодаря API код всего 18 строк.

Применения:

/* Яндекс */
$city = geo_info("213.180.204.8"); // Москва

/* Новосибирский городской сайт */
$city = geo_info("195.93.187.1"); // Новосибирск

/* Самарский инфопортал */
$city = geo_info("195.128.128.21"); // Самара

/* Оф. сайт города Владивостока */
$city = geo_info("93.88.6.150"); // Владивосток

/* "Санкт-Петербург.ру" */
$city = geo_info("85.235.218.197"); // Санкт-Петербург 

/* Неверный IP или данных нет в базе  */
$city = geo_info("000.000.000.000"); // Вернет false

/* IP адрес клиента  */
$city = geo_info($_SERVER["REMOTE_ADDR"]); // Вернет город посетителя

Кэширование вас обязательно спасет от бана. Правда :)

Отзывов (15)

Сен 18 2009

Определение тИЦ и PR с помощью PHP-скрипта

Автор: admin | В рубриках: PHP скрипты

Раз уж мы решили вести свой блог по-хорошему нужно и следить за ним. В плане посещаемости – известности, и если с первым более-менее справляется практически каждая система статистики которых в сети сейчас куча, со вторым всплывают вопросы. Итак, как же определить тематический индекс цитирования (тИЦ) и PageRank (PR) своего сайта с помощью PHP? Очень просто. В этом примере использовались источники которые используются “Google Toolbar” и “Яндекс.Бар” как довольно простые и надежные способы получения этих значений, и если с Яндексом еще альтернативный вариант в виде каталога, то с Google все довольно сложнее(других источников я не встречал). Однако и с каталогом яндекса – далеко не лучший вариант и это имеет ряд сопутствующих проблем. Во-первых, необходимо парсить целую страницу, которая, конечно же, тяжелее в отличие от используемого нами XML варианта, а во-вторых, обновление тИЦ в каталоге происходит несколько медленнее, чем на самом деле. Что есть плохо. Итак, встречайте.

class CY_PR {
  /* http://php-developer.ru/ */
  private function StrToNum($Str, $Check, $Magic) {
      $Int32Unit = 4294967296;
      $length = strlen($Str);
      for ($i = 0; $i < $length; $i++) {
          $Check *= $Magic;
          if ($Check >= $Int32Unit) {
              $Check = ($Check - $Int32Unit * (int) ($Check / $Int32Unit));
              $Check = ($Check < -2147483648) ? ($Check + $Int32Unit) : $Check;
          }
          $Check += ord($Str{$i});
      }
      return $Check;
  } 

  private function HashURL($String) {
      $Check1 = StrToNum($String, 0x1505, 0x21);
      $Check2 = StrToNum($String, 0, 0x1003F);
      $Check1 >>= 2;
      $Check1 = (($Check1 >> 4) & 0x3FFFFC0 ) | ($Check1 & 0x3F);
      $Check1 = (($Check1 >> 4) & 0x3FFC00 ) | ($Check1 & 0x3FF);
      $Check1 = (($Check1 >> 4) & 0x3C000 ) | ($Check1 & 0x3FFF);
      $T1 = (((($Check1 & 0x3C0) << 4) | ($Check1 & 0x3C)) << 2 ) | ($Check2 & 0xF0F );
      $T2 = (((($Check1 & 0xFFFFC000) << 4) | ($Check1 & 0x3C00)) << 0xA) | ($Check2 & 0xF0F0000 ); 

      return ($T1 | $T2);
  } 

  private function CheckHash($Hashnum) {
      $CheckByte = 0;
      $Flag = 0;
      $HashStr = sprintf('%u', $Hashnum) ;
      $length = strlen($HashStr);
      for ($i = $length - 1;  $i >= 0;  $i --) {
          $Re = $HashStr{$i};
          if (1 === ($Flag % 2)) {
              $Re += $Re;
              $Re = (int)($Re / 10) + ($Re % 10);
          }
          $CheckByte += $Re;
          $Flag ++;
      }
      $CheckByte %= 10;
      if (0 !== $CheckByte) {
          $CheckByte = 10 - $CheckByte;
          if (1 === ($Flag % 2) ) {
              if (1 === ($CheckByte % 2)) {
                  $CheckByte += 9;
              }
              $CheckByte >>= 1;
          }
      }
      return '7'.$CheckByte.$HashStr;
  }

  public function check_pr($url) {
    $ch = curl_init("http://toolbarqueries.google.com/search?client=navclient-auto"
                   ."&ch=".$this->CheckHash($this->HashURL($url))."&features=Rank&q=info:$url");
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    $result = curl_exec($ch);
    if(curl_errno($ch) != 0)
      die("curl_errno(".curl_errno($ch)."), curl_error(".curl_error($ch).")");
    curl_close($ch);
    return substr($result, 9);
  }

  public function check_cy($url) {
    $ch = curl_init("http://bar-navig.yandex.ru/u?ver=2&url=$url&show=1");
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    $result = curl_exec($ch);
    if(curl_errno($ch) != 0)
      die("curl_errno(".curl_errno($ch)."), curl_error(".curl_error($ch).")");
    curl_close($ch);
    $xml = simplexml_load_string($result);
    return intval($xml->tcy->attributes()->value);
  }
}

Используется это дело не менее просто:

$cy_pr = new CY_PR();

$url = "http://yandex.ru/";
$pr = $cy_pr->check_pr($url);
$cy = $cy_pr->check_cy($url);

echo "CY: $cy<br />\r\nPR: $pr";

Результат данной операции:

CY: 160000
PR: 8

Эффект достигнут.
P.S. Не забывайте о кэшировании.

Отзывов (4)

Сен 17 2009

Стартап

Автор: admin | В рубриках: Новости

Поехали :)

Отзывов (2)