Резка строк в UTF-8 в PHP
Время от времени в программизме для веб возникает задача обрезать строчку скажем на 1000 символов - чтобы было нечто типа "строка..." и "Читать далее" (как например сделано в этом блоге на слишком длинных заметках. Проблемы начинаются с резкой UTF-8 строк, потому что стандартная функция substr в этом отношении демотивирует - байта на каждый символ два, а она режет по одному... В результате может от какой-нибудь буквы "ё", остаться неприглядный однобайтовый служебный символ.
Если у вас есть расширение php_mbstring - нет проблем, там есть функция , которая корректно обрабатывает юникод. А вот если нету (скажем, на высоконагруженных проектах интерпретатор PHP как правило максимально облегчён - без всяких лишних расширений) то уже сложнее. Однако, выход есть - не обязательно резать по буквам, можно резать по словам. Этот метод я случайно обнаружил в одном из рабочих проектов и просто поразился простоте и эффективности решения такой уже тривиальной задачи. Собственно, сабж:
$arr = explode(' ', $text);
$arr = array_slice($arr, 50);
$text = implode(' ', $arr[0]).'...';
unset($arr);
В результате у нас имеется выборка из 50 слов, которая выглядит куда лучше, чем разрыв слов в неожиданных местах.
Коль хочешь в знаниях прогресс - подпишись на RSS!
О кэшировании в Web
День добрый, дражайший читатель.
Вообще, я не имею уж очень большого опыта в работе с высоконагруженными системами. Обычно проекты, которые мне доводилось делать, были рассчитаны на посещаемость в 20000 человек в сутки. Ну или около того. Однако, однако... Программисты народ странный. Мы иногда делаем нечто "на будущее". Ну вдруг потребуется. Но вначале немного теории. Как строится высоконагруженная система? Основной её компонент - это балансировщик нагрузки. Фактически он просто обеспечивает обработку запроса пользователя одним из нескольких back-end'ов. Например один балансирощик (и лично мне доводилось слышать, что в его роли может выступать например nginx), раскидывает запросы по нескольким PHP-сборщикам (или бросается смотреть в кэш - нет ли уже того, что требуется). Те, соответственно формируют контент, и отдают его обратно. Это очень упрощённо, прямо скажем. Потому что я всё-таки не администратор веб-серверов, и всех тонкостей не знаю.
Так вот, это я к тому, что кэширование - один из действенных способов снижения нагрузки. Зачем выполнять кучу кода для формирования HTML-контента, если такая работа уже была сделана ранее, и с тех пор ничего не поменялось? Правильно, незачем. Так не логичнее ли сохранить страницу в кэш, и отдавать её каждый раз быстро и без мучений? Логичнее, все так и делают. И вот тут есть выбор - где размещать кэш. Существует много вариантов, но если свести к основным, это либо жёсткий диск, либо оперативная память. Чувствуете разницу? Скорость обращения к жёсткому диску в разы ниже, чем к оперативке, но при этом кэширование на жёстком диске подходит практически для любого хостинга, в том числе и виртуального. Однако важно понимать, что высоконагруженные проекты никогда не размещаются на виртуальном хосте. Его мощностей и возможностей просто не хватит для обработки такого потока данных. Потому для просто посещаемых проектов это минимум VPS. А для проектов с высокой нагрузкой необходимо строить распределённую систему с балансировкой, отдельным сервером для БД, для кэшировщика, для контент-сборщиков и так далее. Это дорого, но как правило ресурс окупает подобные затраты.
Даже последний из недотёп всегда RSS читает взахлёб!
Внедрение OpenID на PHP
Таки здравствуй, дражайший читатель.
Вообще, не люблю я писать о работе (хотя статистика количества записей в рубрике соответствующей и ставит под сомнение данное утверждение). Но тут прямо не мог не написать. Все вы, коллеги-PHP-шники, разумеется слышали про такую адову приблуду, как . Если вкратце, то оная позволяет авторизовать пользователей на разных сайтах под одной учётной записью. Например у меня есть почтовый ящик Google, и с его помощью я могу быть авторизован на сайтах, поддерживающих такой вид авторизации. Т.е. мне не надо придумывать пароль/логин, для того, чтобы войти на сайт. При этом сам ресурс не узнаёт лишнего, он знает только то, что я - это я (ибо доверенный openid сервер это подтверждает). Так вот, вроде бы идея то, конечно, хорошая... Однако на пути внедрения оной становятся несколько проблем. Первая - отсутствие более или менее подробной информации по протоколу/стандарту на русском языке. Вторая - большой набор библиотек, позволяющих (теоретически) проводить безболезненное внедрение OpenID авторизации у себя на сайте. Третья - это наличие нескольких стандартов openid (хотя само по себе это не проблема). И четвёртая - это разная степень развитости этих библиотек, напрямую вытекающая из третьей. Есть ещё и пятая - библиотеки используют разные способы общения с серверами авторизации, самый распространённый - это curl-запросы, которые априори требуют наличия в установленном на сервере PHP расширения curl или компиляции, с опцией --with-curl. Вообще на нормальных хостингах он должен быть включен, однако... как показывает практика - не везде он есть. В общем, все дальнейшие рассуждения основываются на том, что curl таки есть, либо есть возможность его поставить. Просто найти библиотеку, которая бы его не использовала - на самом деле очень сложно.
Твой сосед в петлю полез? Ну и хуй с ним - читай RSS!
Водяной знак на PHP+GD
Собственно, совсем недавно была завершена некоторая работа - она была связана с программированием конвейера сборки большого числа изображений из отдельных картинок "конструктора". Для этого, само собой, пришлось накладывать полупрозрачные слои. При теоретических изысканиях данного вопроса - я обнаружил интересную особенность - при запросе "Водяной знак на PHP + GD" в сети нет нормальной, практической информации по этому поводу. Вас сначала погружают в дебри теоретических изысканий, вместо того, чтобы дать самодокументированный код. Я решил пойти иначе. Внизу - функция обеспечивающая наложение водяного знака на изображение. Из недостатков - то, что она работает только с изображениями формата PNG. Впрочем, программисту это исправить не проблема.
function watermark($_source_path, $_watermark_path, $_file='')
{
/* Проверка - подключена ли библиотека GD - если её нет, вам необходимо либо самому подключить эту библиотеку
* (В файле php.ini, секция extensions, необходимо прописать либо раскомментировать строку:
* extension=php_gd2.dll - в windows. */
if (!extension_loaded('gd'))
{
return false;
}
if (!empty($_source_path) && !empty($_watermark_path))
{
$i_source = imagecreatefrompng($_source_path);
$i_watermark = imagecreatefrompng($_watermark_path);
$result = imagecreatetruecolor(imagesx($i_source), imagesy($i_source));
/* Координаты 0,0,0,0 - задают координаты соединения изображений.
* Поигравшись с ними можно изменить положение водяного знака (да и исходного изображения)
*/
imagecopy($result, $i_source, 0, 0, 0, 0, imagesx($i_source), imagesy($i_source));
imagecopy($result, $i_watermark, 0, 0, 0, 0, imagesx($i_watermark), imagesy($i_watermark));
imagedestroy($i_source);
imagedestroy($i_watermark);
if (!empty($_file))
{
imagepng($result, $_file, 4);
}
else
{
return $result;
}
}
}
Чтобы череп не облез - подпишись на RSS!
Библиотечко для сохранения файлов по 300 штук в папке
Собственно говоря, посидел я тут на досуге, поразмышлял о нелёгкой судьбине веб-программиста. Часто приходится думать не только лишь о том, чтобы пообщаться с заливаемым файлом (ну или генерируемым - какова будет воля начальства либо заказчика), но и о правильном сохранении оного. Поясню, что я имею ввиду.
Как вам известно, просмотр одной папки с содержимым из 40 - 50 ТЫСЯЧ файлов любого формата операция достаточно ресурсоёмкая. В системные причины оного я не вникал, но подозреваю следующее. Перед выдачей файла на запрос, сервер лезет в папку указанную в адресе, и делает что-то вроде ls, ну или dir, что одно и то же. Просмотрев весь список файлов и найдя необходимый он выдаёт его юзеру. Тут впору загнуться и статическому веб-сайту, состоящему из одних html страниц. Так или иначе, решение было найдено многими поколениями программистов. В целевой папке (ну, допустим, uploads) создавать много подпапок, например по-номерам (1,2,3), и сохранять в них по фиксированному количеству файлов. Чаще всего по 300 штук.
Проблема по-большей части состоит в том, что каждый раз приходится сей алгоритм реализовать по-новой. Что совсем некошерно. Я в принципе реализовал его в виде универсального класса. Его достоинства в том, что там только два значимых метода: конструктор и функция save.
Работа тривиальна, создаём экземпляр класса FileSaver, в параметрах __construct() передаем:
1. Адрес родительской папки, к примеру /usr/bla/bla/domain.ru/www/uploads/, 2. максимальное количество файлов в подпапках, 3. создавать ли директорию, если она не существует, и 4. права на создаваемую папку.
Затем - каждый раз, когда нам надо сохранить в эту папку файл, мы вызываем метод save(), параметрами которого являются: 1. путь к перемещаемому файлу, должен содержать имя существующего файла, иначе метод вернёт false.
Второй параметр указывает, надо ли перезаписывать имя файла, либо оставить как есть у оригинала.
Третий параметр указывает на то, как формировать имя файла. При значении false он считает sha1-хэш файла, и именем файла ставит его, + расширение файла, если оно было. Этим мы обеспечиваем 1. уникальность имён, 2. уникальность файлов (если кто-то попробует поместить туда идентичный по содержимому файл, то хэши совпадут, и при условии сохранения в одну и ту же подпапку - ничего не выйдет, файл останется на месте). По умолчанию этот режим отключен, и имя файла формируется из текущего значения времени в unix timestamp + миллисекунды + случайное число из диапазона 1-10 + расширение оригинального файла.
ВНИМАНИЕ! Метод save осуществляет ПЕРЕМЕЩЕНИЕ файла со старого места в новое, если вам оно не надо, найдите в методе save участок (помечен комментарием), и измените там rename на copy. Возможно, в будущих версиях я сделаю более гибкую настройку модуля, но пока так.
Метод Save возвращает полный путь по которому был сохранён файл. Если вам надо иначе - в методе есть участок с комментарием, иллюстрирующим, как это сделать.
Вот, собственно, и всё. По мере наполнения структура директорий будет выглядеть так:
/uploads/
-- /1/
-- /2/
-- /3/
И так далее. По мере заполнения директории с крайнем индексом, создаётся новая, со следующим, и вперёд, с песней... Я сохранял туда 100 000 файлов, и потом благополучно делал обращение. Ничего, апач не загибался. Если попробовать сделать то же самое, когда они лежат в одной папке кучей - можно и не дождаться результата.
В заключение: .
Чтобы девушка стонала - подпишись на фид канала!
Обновлён движок (CMS) сайта.
Ну таки здравствуйте.
Сегодня был обновлён движок для сайта "Шпаргалко", сиречь, этого сайта. Прошу любить и жаловать :) В целом он, как и всё в процессе пуско-наладки, сырой. Зато теперь наконец то сделан не просто набор скриптов, а вполне себе модульная система. Если, скажем, захочется добавить какой-то ещё функционал, кроме блога, то это сделать будет уже значительно проще, чем на старой версии (скажу по секрету, весь двжиок был полностью переписан, равно как и структура БД - она значительно изменилась).
Изменения в пользовательской части, в принципе, минимальны. Разве что теперь сайт (имеется ввиду вёрстка) поддерживает W3C стандарт, и валидатор проходит нормально.
Также напоминаю, что тут есть )) На нём 4 пользователя и 7 постов в данный момент.
Пока, собсна, всё :)
Раз - бес. Два - бес. Три - бес...
Допился до чёртиков. Надо скорее читать RSS!
Как преобразовать (изменить) кодировку в PHP
Читал тут в сети кучу опусов на тему определения, преобразования, конвертации кодировок в PHP. Нет, оно всё работает, правда я не понимаю, нахер оно надо, если есть расширение iconv ? Описывать как с ним работать я не буду, ибо там всё элементарно.
Сслыка здесь:
Чтобы Ктулху не воскрес - подпишись на RSS!
Регулярное выражение для проверки email-адреса
Короче сегодня сидел ебался с поиском RegEx - выражения для проверки корректности введённого мыла. После того как потратил 15 минут на поиск в сети, сказал "а ну его на хуй", и поискал в своих старых исходниках. Нашёл. Нате, может кому пригодится :)
// проверка email на корректность
function valid_email($email)
{
return eregi("^[a-zA-Z0-9._-]+@[a-z0-9._-]+.[a-z]{2,4}$", $email);
}
Чтобы Ленин не воскрес - Подпишись на RSS
Расчёт расстояний между двумя точками на поверхности Земли
Встала тут задачка - задан массив точек (с гео. координатами). Есть опорная точка (тоже две координаты). Есть радиус в километрах. Надо посчитать число точек в массиве, которые удовлетворяют условию - т.е. находятся в пределах радиуса.
Есть два пути решения этой задачи. Первый - самый простой. Тупо перебрать массив и на каждом шаге вычислять радиус между двумя точками: опорной и текущей. Если радиус в пределах - выносим его в буфер, а после прохода - возвращаем сам буфер.
Второй - выяснить, какой шаг по географическим координатам соответствует шагу реальному, допустим, в 10 метров? К примеру это 0.00005. Вычисляем сдвиг, и по нему делаем выборку из БД (обычно всё это там хранится) по условию. Получится, правда не радиус, а квадратик. Но то не беда.
По некоторым причинам решили сделать по-тупому, т.е. получить все записи, а потом по ним пройтись.Целый день я ел себе мозг, пытаясь перевести какую-то хуйню и недоразумение (cos(d)) в нормальное число d в радианах, а затем и в километрах. После долгой и пиздецкой ебли, наконец таки нашёл формулу, которая выдаёт РАБОЧЕЕ значение в километрах. Короче вот кусок кода, отвечающий непосредственно за расчёт:
$dist_km = 111.2 * acos( abs(sin($db_latitude)*sin($_latitude) + cos($db_latitude)*cos($_latitude)*cos( abs($db_longitude - $_longitude) ) ) );
Если дядя Моня взял у вас взаймы таки три рубля, и не отдаёт - угрожайте ему подпиской на мой RSS канал... Может быть и не поможет. Но точно и не повредит.
Как отправить POST, GET запросы, а также сымитировать браузер на сайтах с авторизацией…
В общем, недели две назад передо мной встала перспективная задача. Неважно, в чем она заключалась, но смысл в том, что в процессе работы программы (на PHP) она должна была обращаться к разным сайтам, авторизоваться, и прочим образом извращаться с его контентом. Вручную это писать довольно таки долго. Порыскав по сети, нашёл любопытную вещь: . Это класс на 1200 где-то строчек, который позволяет имитировать веб-браузер. Отправлять формы, получать ответ, авторизоваться, и так далее. Короче говоря это уже выполненная задача на 50%. Если перед вами вдруг встала подобная задача, и поисковик привёл вас на этот сайт - то надеюсь, вы нашли что искали - ссылка на проект выше :) Пролистайте исходники, методы класса интуитивно понятны.
Маленький мальчик куда-то полез... Лучше бы он читал RSS!
