В Интернете много статей типа «X PHP Snippets», так зачем писать еще одну? Что ж, давайте посмотрим правде в глаза … фрагменты PHP в них, как правило, хромают. Фрагменты, которые генерируют случайную строку или возвращают $_SERVER["REMOTE_ADDR"]
для IP-адреса клиента, на самом деле не так интересны и имеют скромную полезность. Вместо этого, вот пять фрагментов, которые вы, без сомнения, найдете интересными и полезными, представлены вместе с проблемами, которые их вдохновили. Я надеюсь, что креативность во многих из них вдохновит вас на написание лучшего и более креативного кода в ваших повседневных начинаниях.
1. Генерация CSV
Слишком часто мы видим код, который пытается преобразовать многомерный массив данных в CSV, который выглядит следующим образом:
<?php $csv = ""; foreach ($data as $row) { $csv .= join(",", $row) . "n"; } echo $csv;
Проблема состоит в том, что отдельные элементы не экранированы должным образом, и одно значение с кавычкой или запятой может отбросить синтаксический анализатор, который позже пытается использовать данные CSV. Гораздо лучше использовать встроенную fputcsv()
; он должен выполняться быстрее, потому что его реализация находится в коде C, и он обрабатывает необходимые кавычки / экранирование для вас.
Следующий код оборачивает логику для создания CSV-вывода из массива данных. Он имеет необязательные параметры, позволяющие включать столбцы заголовков и указывать, нужно ли сбрасывать CSV-файл непосредственно в браузер или возвращать вывод в виде строки. Элегантность здесь заключается в использовании потоков с помощью fputcsv()
поскольку для работы функции требуется дескриптор открытого файла.
<?php function toCSV(array $data, array $colHeaders = array(), $asString = false) { $stream = ($asString) ? fopen("php://temp/maxmemory", "w+") : fopen("php://output", "w"); if (!empty($colHeaders)) { fputcsv($stream, $colHeaders); } foreach ($data as $record) { fputcsv($stream, $record); } if ($asString) { rewind($stream); $returnVal = stream_get_contents($stream); fclose($stream); return $returnVal; } else { fclose($stream); } }
С помощью функции toCSV()
в вашем арсенале генерирование CSV становится простым и надежным.
2. Автозагрузка классов
Автозагрузка файлов классов является обычным явлением, но, возможно, вам не нравятся некоторые раздутые, более тяжелые предложения автозагрузчика, предоставляемые различными PHP-фреймворками, или, возможно, вам просто нравится создавать свои собственные решения. К счастью, можно свернуть свой собственный минимальный загрузчик и при этом соответствовать стандарту PSR-0, принятому Рабочей группой по стандартам PHP , который я впервые продемонстрировал в своем блоге .
Стандарт не описывает, какие функциональные возможности поддержки должны предоставляться совместимым с PSR-0 автозагрузчиком (методы регистрации, параметры конфигурации и т. Д.). Если он может автоматически найти определение класса в шаблоне <Vendor Name>(<Namespace>)
, то он соответствует PSR-0. Кроме того, он не указывает родительский каталог для <Vendor Name>
. Дополнительный «пух» большинства реализаций автозагрузчика удобен, если вам нужно указать местоположение с помощью кода, но не нужен, если вы просто используете каталог, уже содержащийся в пути включения PHP.
<?php spl_autoload_register(function ($classname) { $classname = ltrim($classname, "\"); preg_match('/^(.+)?([^\\]+)$/U', $classname, $match); $classname = str_replace("\", "/", $match[1]) . str_replace(["\", "_"], "/", $match[2]) . ".php"; include_once $classname; });
Магия здесь в регулярном выражении, которое разбивает входящее имя на его составные части; имя класса всегда будет в $match[2]
, а $match[1]
имя пространства имен, которое может быть или не быть пустой строкой. Необходимо идентифицировать части, потому что подчеркивание не имеет особого значения в части пространства имен, что делает слепую замену подчеркивания и обратной косой черты неверной.
3. Парсинг данных фиксированной ширины с распаковкой ()
В современном современном мире, наполненном XML и JSON, вы можете подумать, что форматы фиксированной ширины исчезли … но вы ошибаетесь. По-прежнему существует большое количество данных фиксированной ширины, таких как некоторые записи журнала, MARC 21 (библиографическая информация), NACHA (финансовая информация) и т. Д. И между вами и мной у меня все еще есть слабое место для данных фиксированной ширины ,
С данными фиксированной ширины относительно легко работать с такими языками, как C, потому что данные, загруженные в память, идеально совпадают со структурой доступа к данным. Но для некоторых работа с фиксированными данными в динамическом языке, таком как PHP, может быть сложной задачей; свободная типизация языка делает такой доступ к памяти невозможным. И в результате мы часто видим код, который выглядит следующим образом:
<?php // Parse a NACHA header record $row = fread($fp, 94); $header = array(); $header["type"] = substr($row, 0, 1); $header["priority"] = substr($row, 1, 2); $header["immDest"] = substr($row, 3, 10); $header["immOrigin"] = substr($row, 13, 10); $header["date"] = substr($row, 23, 6); $header["time"] = substr($row, 29, 4); $header["sequence"] = substr($row, 33, 1); $header["size"] = substr($row, 34, 3); $header["blockFactor"] = substr($row, 37, 2); $header["format"] = substr($row, 39, 1); $header["destName"] = substr($row, 40, 23); $header["originName"] = substr($row, 63, 23); $header["reference"] = substr($row, 86, 8); print_r($header);
Вы вероятно съеживаетесь. Ничего страшного, я бы не хотел, чтобы такой код был в моем приложении! Это многословно, а индексирование подвержено ошибкам. К счастью, есть лучшая альтернатива: unpack()
.
Документация для unpack()
в руководстве по PHP гласит: «Распаковывает двоичную строку в массив в соответствии с заданным форматом» и показывает примеры использования, экранированные с использованием двоичных данных. Что может быть не сразу очевидно, так это то, что функцию можно использовать для анализа строк фиксированной ширины благодаря спецификатору формата «A», который представляет символ (в конце концов, не является ли строка просто серией битов и байтов?).
Используя unpack()
, приведенный выше пример можно переписать более элегантно, например так:
<?php // Parse a NACHA header record $row = fread($fp, 94); $header = unpack("A1type/A2priority/A10immDest/A10immOrigin/" . "A6date/A4time/A1sequence/A3size/A2blockFactor/A1format/" . "A23destName/A23originName/A8reference", $row); print_r($header);
Строка формата в этом случае представляет собой просто последовательность данных символов, определяющих А, счетчика символов для конкретного поля и имени ключа, которому будут присвоены полученные данные в конечном массиве, разделенные косыми чертами. A6date
например, анализирует 6 символов и делает их доступными как $header["date"]
.
4. Шаблон HTML
В сообществе PHP никогда не было большого консенсуса по поводу шаблонов. Мы все согласны с тем, что желательно разделять HTML и PHP, но сталкиваемся с необходимостью использования библиотек шаблонов, таких как Smarty или Twig . Некоторые указывают на то, что PHP сам по себе является механизмом шаблонов, и спорят со скоростью библиотеки, синтаксисом и т. Д. Другие утверждают, что значительно выиграли от использования DSL, предоставляемого системами шаблонов. Одним из компромиссов является шаблон вашего HTML, чтобы сохранить вещи в чистоте, используя очень минимальный класс, написанный на PHP.
<?php class Template { protected $dir; protected $vars; public function __construct($dir = "") { $this->dir = (substr($dir, -1) == "/") ? $dir : $dir . "/"; $this->vars = array(); } public function __set($var, $value) { $this->vars[$var] = $value; } public function __get($var) { return $this->vars[$var]; } public function __isset($var) { return isset($this->vars[$var]); } public function set() { $args = func_get_args(); if (func_num_args() == 2) { $this->__set($args[0], $args[1]); } else { foreach ($args[0] as $var => $value) { $this->__set($var, $value); } } } public function out($template, $asString = false) { ob_start(); require $this->dir . $template . ".php"; $content = ob_get_clean(); if ($asString) { return $content; } else { echo $content; } } }
Это не полноценный шаблонизатор; скорее лаконичный вспомогательный класс, который действует как «корзина» для сбора пар данных ключ / значение, к которым вы можете обращаться во включаемых файлах, обозначенных как шаблоны. Сначала вы создаете экземпляр класса Template
в своем представлении, при желании передавая имя каталога, используемое для поиска последующих файлов шаблона (позволяя группировать связанные файлы). Затем укажите значения, которые должны заполнять шаблоны, либо в метод set()
либо в виде пустого свойства. Когда все значения указаны, вы вызываете метод out()
для визуализации шаблона.
<?php $t = new Template(); // setting a value as if it were a property $t->greeting = "Hello World!"; // setting a value with set() $t->set("number", 42); // setting multiple values with set() $t->set(array( "foo" => "zip", "bar" => "zap" )); // render template $t->out("mytemplate");
Файл mytemplate.php
для примера может выглядеть примерно так:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> ... </head> <body> <div role="main"> <h1><?=$this->greeting;?></h1> ... </div> </body> </html>
В файлах шаблонов у вас есть доступ ко всему спектру функций PHP для форматирования значений, фильтрации значений и т. Д. По вашему усмотрению.
Второй, необязательный параметр to out()
может указывать, что нужно возвращать содержимое шаблона в виде строки, а не сбрасывать его непосредственно в браузер, что можно использовать для замены заполнителей в одном шаблоне результатом ранее заполненного шаблона.
5. Использование file_get_contents в качестве альтернативы cURL
cURL — надежная библиотека для связи по различным протоколам. Это, безусловно, очень полнофункциональный, и бывают моменты, когда ничего не подойдет. Если вам явно нужна функциональность, предоставляемая cURL для выполнения вашей задачи, тогда используйте cURL! Но большинство повседневного использования cURL в PHP вращается вокруг выдачи HTTP-запросов GET и POST, что легко сделать с помощью встроенных функций PHP.
Проблема с использованием cURL для выдачи HTTP-запросов является двоякой: 1) часто существует множество опций, которые необходимо установить, даже для самых простых транзакций, и 2) это расширение, которое может или не может быть доступно в зависимости от на вашем хостинге и ситуации с установкой; это общее расширение, но оно не включено по умолчанию.
file_get_contents()
и stream_context_create()
— две нативные функции PHP, которые были доступны с 4,3 дня. Вместе они могут использоваться для выполнения множества однотипных запросов, обычно выполняемых через cURL.
Для основных запросов GET file_get_contents()
может использоваться сам по себе:
<?php $html = file_get_contents("http://example.com/product/42");
Для запросов, в которых вам нужно указать заголовки HTTP, будь то GET или любой другой метод HTTP, вы можете создать контекст, передав массив со специальными stream_context_create()
в stream_context_create()
а затем передать контекст в file_get_contents()
.
<?php $context = stream_context_create(array( "http" => array( "method" => "POST", "header" => "Content-Type: multipart/form-data; boundary=--foorn", "content" => "--foorn" . "Content-Disposition: form-data; name="myFile"; filename="image.jpg"rn" . "Content-Type: image/jpegrnrn" . file_get_contents("image.jpg") . "rn" . "--foo--" ) )); $html = file_get_contents("http://example.com/upload.php", false, $context);
-<?php $context = stream_context_create(array( "http" => array( "method" => "POST", "header" => "Content-Type: multipart/form-data; boundary=--foorn", "content" => "--foorn" . "Content-Disposition: form-data; name="myFile"; filename="image.jpg"rn" . "Content-Type: image/jpegrnrn" . file_get_contents("image.jpg") . "rn" . "--foo--" ) )); $html = file_get_contents("http://example.com/upload.php", false, $context);
В приведенном выше примере показана загрузка файла через POST, причем массив контекста задает необходимую информацию для транзакции с использованием ключей «method», «header» и «content».
При использовании file_get_contents()
для сложных запросов, таких как загрузка файлов, может быть полезно сначала создать фиктивную веб-форму и запустить ее через Firefox с включенным firebug или чем-то подобным, а затем проверить, что было включено в запрос. Оттуда вы можете вывести важные элементы заголовка для включения.
Резюме
Надеюсь, вы нашли интересные фрагменты, представленные в этой статье. Они демонстрируют творческое решение проблем и использование встроенной функциональности PHP для нового эффекта. Я надеюсь, что вы найдете их полезными и вдохновляющими. И если у вас есть собственные вдохновляющие фрагменты, не стесняйтесь поделиться в комментариях ниже.
Изображение через Fotolia