php
PHP 5.2.5 высыпается в кору
Если у вас PHP 5.2.5 высыпается в кору и gdb показывает, что ошибка произошла в sapi_deactivate, поставьте патч из CVS, должно помочь.
PHP2EXE
Решил посмотреть что у нас на старую добрую тему php2exe — т. е.
Вот этот компилятор я и скачал. Версия 2.9.0, бета. Первое, что я выяснил, когда нашёл где включается режим вывода лога компиляции, инсталлировать надо было туда, куда программа предлагала по умолчанию. Путь «Program Files» вызывает проблемы
В итоге, эксперимент окончился плачевно. Мало того, что итоговый файл оказался размером шесть мегабайт (при том, что исходная программа занимает 1.5 килобайта) — это ещё терпимо, понятно, что с ростом исходной программы этот размер меняться почти не будет, да и упаковывается он до одного мегабайта, например, при помощи NPack. Хуже, что скомпилированная (даже не сжатая) программа так и не заработала — при выполнении возникают ошибки переполнения.
Вывод: возможно, это огрехи
Генерация «трафки™» или распределение по весам
Дима Смирнов применил интересное решение для генерации «трафок» на «Блоговаре»:
$rb = str_pad (decbin (mt_rand (0,64)),6,"0", STR_PAD_LEFT);
$herb = (int) strpos ($rb, "1");Смысл в том, что каждое следующее значение должно выпадать с вдвое меньшей вероятностью, чем предыдущее. Пока я спал, мне пришло в голову довольно забавное решение на ту же тему. Оно быстрее примерно на 30%, не обладает ограничением на размер и точнее вычисляет вероятности (у Димы «трафка» не выпадает с вероятностью примерно 52%), но не решает задачу полностью. Кто скажет в чём разница, не запуская код?
for ($i = 5; $i && mt_rand(0, 1); --$i);Сайт на мобильных устройствах: Wall4PHP
Латвийский парень Kaspars Foigts реализовал библиотеку Wall4PHP. Это реализация WALL (Wireless Abstraction Library, оригинальная версия создана Luca Passani на Java) на языке PHP. Библиотека предназначена для поддержки сайтом мобильных устройств и позволяет на специальном языке описывать вёрстку, чтобы потом показывать сайт на том языке, который поддерживается устройством (XHTML, WML, модифицированный HTML
Профиль устройства (что именно им поддерживается) описывается на специальном
Разделяемая память
Удивительная вещь — до появления memcached никто, как будто бы, и не знал о существовании разделяемой памяти. Сейчас memcached
Кроме того, у memcached есть особенность, которую тоже надо учитывать. Есть случаи, когда memcached может удалить данные из кеша, вот комментарий разработчика Анатолия Воробья:
Есть набор классов по величине памяти — например, в самом простом и дефолтном варианте, есть класс размером в 128 байт, потом 256 байт, потом 512, 1k, 2k итд. до 1Mb. Если
какая-то запись (ключ+значение+ дополнительные заголовки) занимает, скажем, 1.5k, под нее отводится кусок из класса в 2k, т. е. кусок размером в 2k, и она в него пишется.У каждого класса отдельно есть своя LRU queue всех записей в этом классе — каждый раз, когда
кто-то просит прочестькакую-то запись, она перемещается в начало списка своего класса. Таким образом, в конце списка находятся те записи, которых давно никто не просил — их куски освобождаются, когда нужно место для новой записи в этом классе, и нельзя больше согласно конфигурации попросить памяти у системы.
Ссылки на другие способы доступа к разделяемой памяти есть в аннотации к модулю PEAR System::SharedMemory.
Скорость замены в PHP
Провёл небольшие замеры в PHP. Задача следующая — заменить вхождения между двумя ограничителями (в моём случае — фигурные скобки) по хешу, где ключём хеша является значение, которое заменяем, значением хеша — то, на что заменяем. Сделал несколько реализаций, с использованием различный функций (слева функция, справа — время в секундах замены из одного и того же словаря на приличного размера тексте):
strpos — 0.23691987991333
explode — 0.27920699119568
preg_replace_callback — 0.34914493560791
str_replace — 1.8960340023041
strtr — 3.1935269832611
Во многом результаты довольно ожидаемые,
Загадки PHP
Да что это я всё о себе, да о себе? Давайте я вам лучше о PHP расскажу! PHP, несмотря на кажущуюся простоту, язык уникальный своими загадками. Возникают, они, в основном
Ссылки в PHP — совершенно особая сущность. Небольшой ликбез. Ссылка — это способ «соединить» две переменные так, что меняя значение одной, меняется значение второй и наоборот. Записывается ссылка очень просто: $foo = &$bar. Кажущаяся простота ссылок обманчива. Я сейчас буду рассматривать PHP5, поскольку мне кажется, что четвёртая версия должна умереть как можно скорее. Все примеры были проверены под PHP 5.1.4 и PHP 5.2.0RC1 под Windows и Linux.
<?php
$a = new stdClass();
function Bar($bar)
{
$bar->val = 1;
}
Bar($a);
print_r($a);Проблема номер раз. Как вы думаете, что напечатает print_r? Отвечу сразу: он покажет свойство «val» со значением «один». Почему так произошло? Дело в том, что в PHP5 (как и во многих других языках) все объекты передаются по ссылке. Это значит, что переменная $bar в функции ссылается на переменную $a, которую мы указали в качестве параметра и все изменения $bar коснутся переменной $a. Если мы вызовем функцию «Bar» с другим параметром, то $bar будет ссылаться на этот новый параметр.
Ситуация, когда объект в функцию нужно передать по значению, на практике — почти невероятна, впрочем, если она и возникнет, объект всегда можно клонировать — в PHP5 есть специальные конструкции.
<?php
$v = array(1);
$b = &$v[0];
$c = $v;
$v[0] = 100;
echo $c[0];Проблема номер два. Что же будет внутри $c[0]? Странно, но — 100. Как же так? Всё просто. В PHP, если мы создали ссылку на переменную, то оба имени переменных становятся ссылками. Получается, что присваивая $c внутренность $v, я его присваиваю вместе с $v[0], которая стала ссылкой.
Странно? Совсем нет. Дело в том, что имя переменной — это тоже ссылка. Ссылка на область памяти, где записано её значение. Если ссылок на место, занимаемое переменной, больше чем одна, то все её имена ведут себя как «ссылка», если же удалить «лишние», то последнее имя теряет свою «ссылочность». Пример:
<?php
$v = array(1);
$b = &$v[0];
var_dump($v);
unset($b);
var_dump($v);Первый «var_dump» покажет нам ссылку, второй — нет.
<?php
$bar = 1;
function Foo()
{
global $bar;
$test = 100;
$bar = &$test;
}
Foo();
echo $bar;Проблема номер три. Кстати говоря, когда вы используете конструкцию «global», на деле вы используете ссылку. Дело в том, что «global $bar» полностью эквивалентна «$bar =& $GLOBALS[’bar’]». Если вы не знаете что такое $GLOBALS, самое время открыть руководство по PHP и узнать. Так вот. Проблема заключается в том, что «магическое» слово «global» прячет от нас всю эту операцию, поэтому кажется, что в глобальной переменной $bar должно быть значение 100. Это не так.
На деле, «$bar = &$test» вызовет переназначение ссылки. То есть, прежняя ссылка «$bar — это $GLOBALS[’bar’]» пропадёт и на её место встанет «$bar — это $test». Значение $GLOBALS[’bar’], естественно, не изменится.
Ну а теперь, вооружённые этими новыми знаниями, мы рассмотрим следующий интересный пример.
<?php
$v = array(1);
foreach ($v as &$item) echo $item;
function Bar($foo)
{
$foo[0] = 100;
}
Bar($v);
var_dump($v);Итак! Что выведет «var_dump»? Правильно — 100. Почему? Вполне логично — в цикле мы проходим по элементам массива, причём $item ссылается на текущий элемент как ссылка. После цикла остаётся ссылка «$item — это $v[0]», поэтому, когда я передал в «Bar» переменную $v, её нулевой элемент остался ссылкой. Остальное понять труда не составляет. Давайте пойдём дальше.
<?php
$v = array(1, 2);
foreach ($v as &$item) echo $item;
function Bar($foo)
{
$foo[0] = 100;
$foo[1] = 100;
}
Bar($v);
var_dump($v);Что же тут покажет «var_dump»? Странно, но в обоих элементах массива будет… 100. Казалось бы — bug PHP (впрочем, я не настаиваю — может это и баг). Оказывается, не совсем. Дело в том, что ссылка в PHP уничтожается конструкцией unset и только ей. При переприсвоении ссылки прежняя ссылка не удаляется, точнее, PHP не трогает счётчик ссылок. В моём следующем примере все три переменные будут ссылкой (в чём легко убедиться, сделав «var_dump переменной $GLOBALS»):
<?php
$v = 1;
$k = 2;
$b = &$v;
$b = &$k;Первый же unset «восстановит справедливость»:
<?php
$v = 1;
$b = &$v;
$t = &$v;
$k = 2;
$b = &$k;
unset($t);Теперь переменные $k и $b — ссылочные, а $v — нет. Видимо, «пересчёт» ссылок при пересвоении вызывает
PHP для PocketPC
Одной из особенностей языка PHP является то, что существует ровно один интерпретатор этого языка. Это хорошо — никакого разночтения стандартов и прочих проблем наличия интерпретаторов от разных команд. Или, по крайней мере, другие мне не попадались. До сих пор.
Некие умельцы написали Pocket HPH — интерпретатор для PocketPC. Конечно, реализованы далеко не все функции, но и того набора, что есть, хватит, чтобы реализовать
Библиотека для работы с XBM и моно-BMP
Одним словом,
Разделяемая память и PHP
В основном на PHP пишут небольшие проекты, поэтому литература кишит примерами «как сделать сайт в три странички». Но, тем не менее, только простыми сайтами дело не ограничивается. Когда приходится делать производительные проекты, существует множество ухищрений и решений, одно из которых — использовать разделяемую память, там где кешировать данные в статические файлы не получается. Различных API для использования разделяемой памяти много, только в одном PHP есть shmop, shm_* и Memcache, что несколько осложняет дело.
Я сделал
В настоящий момент поддерживаются следующие API:
- eAccelerator
- Turck MMCache
- APC
- Shmop
- Apache Notes
- Memcached
- System V (имена переменных до 4х символов)
- SQLite (база данных создаётся в памяти)
- Sharedance
- File (данные хранятся в файлах)
Brainfuck
Дело давнее, но около месяца назад, поддавшись
Модуль к PHP написан в формате PEAR, т. е. его можно либо использовать непосредственно, либо исталлировать в составе PEAR.
Нельзя сказать, что я компилятор проводит глубокую оптимизацию, но, например, код
<?php
$in = array(0, $id = 0);
$d = array_fill(-65535, 65535, $di = 0);
$d[$di+1]+= $d[$di];
$d[$di+2]+= $d[$di]*2;
$d[$di] = 0;
$d[$di+1]+= $d[$di];
if ($d[$di]) $d[$di+2] = 0;
$d[$di] = 0;
$d[$di+1]+= $d[$di];
$d[$di] = 0;В сам
Блоки и локальные переменные в PHP
Давайте я опять про программирование, ага? Вообще, пусть это будет основной темой моего блога. Общечеловеческие ценности, безусловно, меня тоже волнуют, но это насколько скользкая тема, что так и норовишь вляпаться
Рассуждал я
Не хватает мне возможности изоляции переменных. Чтобы можно было, не задумываясь нет ли вверху
<?php
{
var $i;
echo $i = 1;
}
echo $i;Пояснять нужно? Переменная, объявленная в фигурных скобках, перестаёт существовать за их пределами и не влияет на значения переменной с тем же именем, объявленной уровнем ниже. Я даже согласен на специальную конструкцию (хотя вот эта была бы предельно совместимой), чтобы это включили в PHP6, вместо пространств имён, которые, на мой взгляд, успешно подменяются объектами.
Наверное, нужно пояснить зачем, собственно, это нужно. Поясняю. Для уменьшения расхода памяти, чтобы объект, однажды объявленный в начале файла для локальных нужд, который забыли удалить не тянулся по всему коду, как смрад за народным ополчением, а сразу же, по выходу из блока, попал б в кандидаты на удаление.
Вторая причина — у вас никогда такого не было, что вы перетёрли переменную, которая используется
На мой взгляд, реализовываться это должно довольно просто. Ведь это, по сути, просто анонимная функция со ссылками на все глобальные переменные внутри, где var просто очищает такую ссылку.
Формат графики XBM
Есть такой интересный принцип дарить подарки — покупать в подарок то, что люди сами бы себе никогда не купили. У меня, похоже, одно из хобби — копать там, где ничего не растёт. В том смысле, что меня больше увлекают проекты, где практической пользы меньше, чем льда на Солнце.
Было время, меня увлёк графический формат XBM, единственное достоинство которого (впрочем, вполне достаточное, на мой взгляд) — безумная простота, позволяющая манипулировать графикой в этом формате из любого хоть
И вот я узнаю, что Internet Explorer 6.0SP1 и выше не поддерживает мой любимый формат! Причину цитирую:
A change was made to Internet Explorer for Windows XP Service Pack 2 and Windows Server 2003 Service Pack 1 so that it does not render the XBM image file format. This update adds this change to all other supported versions of Internet Explorer. This change has been made to help prevent the Internet Explorer process from closing unexpectedly when users view
invalidly-formed images. The XBM format is no longer supported by Internet Explorer.
Что переводится, примерно, так: «у нас
Image_MonoBMP — модуля для работы с монохромными изображениями в формате BMP. А чтобы подтвердить, что я опять дарю вам то, что вы себе сами бы не купили, скажу, что этот формат, конечно, поддерживается Internet Explorer и Opera, но FireFox плевать на него хотел, да,
Кстати, есть у меня идея сделать поддержку WBMP, но как же быть с принципом? Впрочем, я его уже нарушил, но об этом
Sort в PHP
Оказывается функция sort в PHP не использует установки локали в PHP4. Косвенно это можно узнать из руководства:
Sorting type flags:
SORT_REGULAR — compare items normally
SORT_NUMERIC — compare items numerically
SORT_STRING — compare items as strings
SORT_LOCALE_STRING — compare items as strings, based on the current locale. Added in PHP 5.0.2
Параметр SORT_LOCALE_STRING появился только в PHP 5.0.2. На мой взгляд, это очень странно. Valshooter рекомендует в этом случае использовать
usort($fruit, 'strcoll');правда, в том случае, если локаль у вас UTF8 вряд ли сортировка вернёт осмысленные данные.
myPHPinfo
Известно, что некоторые хостеры отключают функцию phpinfo из соображений безопасности. Неприятно, но часто приходится мириться и делать
Именно для таких случаев я написал myPHPinfo — программу на PHP, эмулирующую вывод функции phpinfo, насколько это возможно, конечно. Инструкции, ссылки для скачивания и изучения примеров работы есть в специальном разделе сайта.
Наученный горьким опытом даю совет: если вам кажется, что «зачем это нужно, если есть phpinfo», то перечитайте текст выше — там как раз об этом.
Новый 8sender
Обновился 8sender (PHP) — программа, позволяющая отправлять
Новое в этой версии:
- Имена передаваемых файлов записываются ещё и в тему письма.
E-mail отправителя теперь можно не указывать — в этом случае
система автоматически подставит «admin@example.com»
Напоминаю, что для того, чтобы использовать эту программу, вам нужен интерпретатор языка PHP (минимально — файлы php.exe и php4ts.dll).
Для удобства тех, кто работает под Windows я сделал специальный файл — 8sender.bat. Скачивать и запускать нужно его, в пределах видимости скрипта должен быть расположен файл php.exe — той же папке или в любой папке, указанной в системной переменной PATH.
Плохие новости владельцев Windows 95/98/ME — вам придётся указать SMTP сервер для отправки сообщений. Инструкцию по запуску можно получить, запустив программу без параметров.
Сессии в SSI
Один из проектов, в разработке которого я участвовал в недавнем времени, расчитывался на огромную посещаемость (забегая вперёд, скажу — проект действительно стал исключительно посещаемым), в связи с чем пришлось разрабатывать и использовать технические решения, позволяющие проекту не «падать» под огромными нагрузками.
В частности, была разработана система кеширования, которую можно охарактерировать как «всё по максимуму в в HTML, остальное — включаем через SSI и фреймы». Поскольку на сайте используются пользовательские сессии, сложилась ситуация, когда сессию должны могли инициировать и скрипты (язык программирования — PHP, основной сервер — Apache 1.x), включенные через SSI. Тут надо заметить, что
Trans_sid использовать нельзя, скрипты, включенные через SSI заголовок выдать не могут и, следовательно, проставить сессию в cookie — тоже. Сначала я, было, решил полностью отказаться от SSI и работать исключительно с iframe, но подумал — нельзя ли Apache заставить генерировать идентификатор сессии самостоятельно?
Оказалось — можно. Первое, что пришло в голову — использовать модуль mod_unique_id к Apache — я слышал об этом модуле, но никогда его не использовал. Внимательно прочитав инструцию к модулю, я понял, что это совсем не то, что нужно — модуль генерирует уникальный идентификатор для каждого запроса:
This module provides a magic token for each request which is guaranteed to be unique across «all» requests under very specific conditions. The unique identifier is even unique across multiple machines in a properly configured cluster of machines.
Внимательно пролистав список официальных модулей Apache, я нашёл в списке mod_usertrack — модуль, маркирующий пользователей при помощи cookie. Обычно он используется для того, чтобы различать пользователей в логах
Проведя испытания, я столкнулся с вполне ожидаемыми трудностями — во время первого запроса, когда сервер только что отослал cookie клиенту, в переменной PHP \_COOKIE$ пусто — cookie ещё не пришли от клиента назад и, соотвественно, не были записаны в эту переменную.
В PHP есть функция apache_response_headers, возвращающая массив всех заголовков, выдаваемых
<?php
function U_sid()
{
// Если идентификатор уже есть в cookie, возвращаем его
if (isset($_COOKIE['Apache'])) return $_COOKIE['Apache'];
// Иначе - ищем его в ответе Apache
$responce = apache_response_headers();
foreach (preg_split('/s*;s*/', @$responce['Set-Cookie']) as $chunk)
{
list($key, $value) = explode('=', $chunk, 2);
if ($key == 'Apache') return $value;
}
return null;
}«Apache» — это имя cookie, которое проставляет Apache. Далее — всё просто, в php.ini отключаем «session.use_trans_sid» и «session.use_cookies», чтобы запретить PHP создавать сессии, в .htaccess помещаем директивы модуля mod_usertrack:
CookieFormat Compact CookieTracking on CookieStyle CookieА в библиотечный файл (или наши файлы PHP, поближе к началу), вызов необходимых, для создания сессии, функций:
<?php
// Узнаём идентификатор сессии
if (($sid = U_sid()) !== null)
{
// Если он не null, создаём сессию
session_id($sid);
session_start();
}В итоге мы получаем
8sender
Написал программу (2.65Кб), позволяющую отправлять вложения в формате bolk quoted printable. На PHP. Вкратце напомню — это формат, который, в отличие от остальных форматов вложений (quoted printable, UUE, Base64), минимально увеличивает размер файла. Основные почтовые клиенты его понимают.
Утилита
php 8sender.php mail@example.com bolk@example.net big.tiffОпционально первым параметром можно указать адрес вашего SMTP, он должен быть первым после ключа -t. Если его не указать, программа попытается самостоятельно определить MX получателя. Для работы под Windows желателен PHP 4.3.0 и выше.
php 8sender.php -t smtp.example.com mail@example.com bolk@example.net big.tiffПосле запуска программа покажет диалог
Устранение потерь при кодировании почтовых аттачей в base64
Как известно,
Прошло время, текст в электронных письмах давно уже не только английский, а стандарты кодирования текстовых файлов до сих пор используют только латинские буквы (плюс цифры и некоторые символы, такие как плюс, миную, слеш и так далее). Мне пришло в голову — а что если попробовать кодировать файлы всем полем допустимых символов. Сейчас, когда появились письма
Из всех вариантов кодирования, а их три (Base64, UUencode
Я же задался целью проверить, что же будет, если попробовать передать файл, где поле допустимых символов расширено до максимума. Сразу скажу — эксперимент удался. Можено эксперементально внедрять новый формат кодирования писем. Назовём его Bolk
Я написал небольшую программу на PHP, которая в качестве параметра использует имя файла, который нужно закодировать, а на выход выдаёт этот файл в формате понятном почтовому клиенту. Таким образом, если её запустить как «php -q 8qp.php somegif.gif > somename.eml» и открыть получившийся файл вашим почтовым клиентом, внутри вы должны увидеть свою картинку.
<?php
// Example 1. 8qp.php
// Written by Evgeny Stepanischev aka BOLK
$bound = 'BOLKNOTE.RU';
$mime = getimagesize($argv[1]);
$mime = $mime['mime'];
$str = file_get_contents($argv[1]);
$len = filesize($argv[1]);
echo <<<HEADER
Content-Type: multipart/mixed;
boundary="----{$bound}"
------{$bound}
Content-Type: $mime; name="{$argv[1]}"
Content-Disposition: attachment; filename="{$argv[1]}"
Content-Transfer-Encoding: quoted-printable
HEADER;
$np = array (0, 10, 13, 61);
for ($i = 0; $i<$len; $i++)
{
$code = ord($str{$i});
echo in_array($code, $np) ?
'='.strtoupper(str_pad(dechex($code), 2, '0', STR_PAD_LEFT)):
$str{$i};
}
echo "rn------{$bound}--";Для эксперимента я выбрал наугад две картинки. JPEG и GIF. И вот что получилось в итоге. «TheBAT!» — это наименование моего почтового клиента.
Случайный GIF: исходный размер — 33590, мой
Случайный JPEG: исходный размер — 28144, мой
В случае
Эксперименты на первом же попавшемся Sendmail показали, что,
Последняя беда поставила меня в тупик. Правда, ненадолго. Вспомнив, что большинство клиентов умеют открывать письма в формате EML я решил пойти на хитрость — прикрепить моё письмо как аттачмент другого, замаскировав моё письмо под обычный текст — Sendmail вряд ли проверяет аттачи глубже одного вхождения. А чтобы письмо максимально адекватно воспринималось почтовым клиентом, я дал ему disposition inline и убрал из него все служебные поля. Попробовал отправить — получилось. В TheBat видно только лишнее пустое поле — беда небольшая.
<?php
// Example 2. 8qp_next.php
// Written by Evgeny Stepanischev aka BOLK
$bound = '3D1E1C92aaBF00D';
$bound2 = '3D1E1C92xxBF00D';
$mime = getimagesize($argv[1]);
$mime = $mime['mime'];
$str = file_get_contents($argv[1]);
$len = filesize($argv[1]);
echo <<<HEADER
From: <mailbox@sample.com>
To: mailbox@sample.com
From: mailbox@sample.com
Content-Type: multipart/mixed;
boundary="----------{$bound2}"
------------{$bound2}
Content-Type: message/rfc822; name="1.eml"; charset=utf-8
Content-Disposition: inline; name="1.eml"
Content-Transfer-Encoding: 8bit
Content-Transfer-Encoding: 8bit
Content-Type: multipart/mixed;
boundary="----{$bound}"
------{$bound}
Content-Type: $mime; name="{$argv[1]}"; charset=utf-8
Content-Disposition: attachment; filename="{$argv[1]}"
Content-Transfer-Encoding: quoted-printable
HEADER;
$np = array (0, 10, 13, 61);
for ($i = 0; $i<$len; $i++)
{
$code = ord($str{$i});
echo in_array($code, $np) ?
'='.strtoupper(str_pad(dechex($code), 2, '0', STR_PAD_LEFT)):
$str{$i};
if ($i && ($i % 512) == 0) echo "=rn";
}
echo "rn------{$bound}--",
"rn------------{$bound2}--";Полный размер письма после такой двойной «упаковки» увеличивается незначительно. Кстати говоря, Opera 7.0 с таким письмом не справилась. Возможно, в силу старости — текущая версия этого пакета — 7.61b. Для интереса я отправил письмо на мои ящики на серверах Mail.ru и Gmail.com. Оба сервера вполне достойно справились с задачей, единственно, что Gmail не принимал письмо, пока я не указал charset как
Патч к IMP/Horde
Если при работе с webmail IMP/Horde у вас выдаются ошибки в функции imap_fetchbody, попробуйте применить мой патч. Порядок применения:
- Разместить в папке lib, с названием, например, bolkpatch.php.
- В файлах lib/IMP.php и view.php после блока строк require_once надо ставить строку
require_once IMP_BASE . ’/lib/bolkpatch.php’; - Заменить в этих двух файлах все вызовы imap_fetchbody на imap_fetchbody2.
- Установить модуль PEAR Mail_Mime (pear install Mail_Mime)
// IMP patch. Written by Evgeny Stepanischev
function imap_fetchbody2(&$imap_stream, $msg_number, $part_number, $options = NULL)
{
$params = array(&$imap_stream, &$msg_number, &$part_number);
if ($options !== NULL)
$params[] = &$options;
$str = @call_user_func_array('imap_fetchbody', $params);
if ($str == '' || $str === FALSE)
{
array_splice($params, 2, 1);
$mail = @call_user_func_array('imap_fetchheader', $params).
@call_user_func_array('imap_body', $params);
require_once 'Mail/mimeDecode.php';
$decoder =& new Mail_mimeDecode($mail);
$structure = (array) $decoder->decode(array('include_bodies' => true));
return isset($structure['parts'][$part_number-1]) ?
$structure['parts'][$part_number-1]->body :
$structure['body'];
}
return $str;
}