Новый портал о CodeIgniter

Товарищь 2bj (спасибо ему) в твиттере подкинул ссылочку на портал о CodeIgniterCodeIgniter Directory. Сайт на английском, пока там информации не очень много и она вся на английском, но думаю он вскоре разовьется во что-то стоящее.

Кстати, раз тема зашла о CodeIgniter, помните я говорил о blaze cms, так вот, всем советую посмотреть на версию v.1

Далее

Синхронные HTTP запросы в php, используя cURL

Перевод заметки Simultaneuos HTTP requests in PHP with cURL с блога phpied.com
Основная идея Веб 2.0 машапов получение данных от стороннего сервиса или сервисов и обработка их результатов представленная в интересном ключе. Это означает, что вам придется отправлять большое количество HTTP запросов к этому сервису или сервисам. Если вы воспользуетесь PHP функцией file_get_contents (), то запросы будут выполняться не синхронно, а поочерёдно, то есть пока не будут получены данные от первого запроса второй запрос не будет выполнятся. А если вам нужно выполнить три запроса и каждому из них необходима одна секунда на исполнение, то ваше приложение «задумается», по меньшей мере, на три секунды.

Решение
Конечно, можно и нужно использовать кэширование запросов, но первоначально запросы все же нужно делать.
Используя семейство curl_multi* cURL-функций можно достичь синхронного выполнения запросов. В этом случае ваше приложение «задумается» на промежуток равный затраченному времени на самый трудоемкий запрос, в противовес сумме времени всех запросов.
Реализация
Представляю вам свою функцию которая позволит вам выполнять запросы синхронно.

PHP:
  1. <?php
  2.  
  3. function multiRequest($data, $options = array()) {
  4.  
  5.   // массив curl дескрипторов
  6.   $curly = array();
  7.   // массив с возвращенными данными
  8.   $result = array();
  9.  
  10.   // инициализация многосложного curl дескриптора
  11.   $mh = curl_multi_init();
  12.  
  13.   // цикл по элементам массива $data:
  14.   // инициализация простых curl дескрипторов
  15.   // и добавление их к многосложному curl дескриптору
  16.   foreach ($data as $id => $d) {
  17.  
  18.     $curly[$id] = curl_init();
  19.  
  20.     $url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d;
  21.     curl_setopt($curly[$id], CURLOPT_URL,            $url);
  22.     curl_setopt($curly[$id], CURLOPT_HEADER,         0);
  23.     curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1);
  24.  
  25.     // определяем тип передачи параметров в запросе
  26.     // GET или POST
  27.     if (is_array($d)) {
  28.       if (!empty($d['post'])) {
  29.         curl_setopt($curly[$id], CURLOPT_POST,       1);
  30.         curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']);
  31.       }
  32.     }
  33.  
  34.     // указываем дополнительные опции, если нужно
  35.     if (!empty($options)) {
  36.       curl_setopt_array($curly[$id], $options);
  37.     }
  38.  
  39.     curl_multi_add_handle($mh, $curly[$id]);
  40.   }
  41.  
  42.   // выполняем запрос
  43.   $running = null;
  44.   do {
  45.     curl_multi_exec($mh, $running);
  46.   } while($running> 0);
  47.  
  48.   // получаем данные и уничтожаем дискриптор
  49.   foreach($curly as $id => $c) {
  50.     $result[$id] = curl_multi_getcontent($c);
  51.     curl_multi_remove_handle($mh, $c);
  52.   }
  53.  
  54.   // закрываем многосложный дескриптор
  55.   curl_multi_close($mh);
  56.  
  57.   return $result;
  58. }
  59.  
  60. ?>

Итог
Функция принимает в качестве аргументов массив URL’ов и опционально дополнительный параметры cURL опций. Первый массив может иметь простую численную индексацию или это может быть массивом массивов, где второй ключ должен иметь имя «url». Если вы пользуетесь вторым способом, вы также можете добавить ключ «post», тогда данные будут передаваться методом POST.
Функция возвращает массив строк содержащих результат запроса (ответ сервиса) с той же индексацией, что и в массиве с параметрами запроса.

GET пример
Допустим вы решили воспользоваться сервисом поиска от Yahoo (документация на YDN) для создания машап сервиса энциклопедии музыкальных исполнителей. Выполнением следующего кода вы получите результаты поиска по аудио, видео и изображениям одновременно:

PHP:
  1. <?php
  2.  
  3. $data = array(
  4.   'http://search.yahooapis.com/VideoSearchService/V1/videoSearch?appid=YahooDemo&query=Pearl+Jam&output=json',
  5.   'http://search.yahooapis.com/ImageSearchService/V1/imageSearch?appid=YahooDemo&query=Pearl+Jam&output=json',
  6.   'http://search.yahooapis.com/AudioSearchService/V1/artistSearch?appid=YahooDemo&artist=Pearl+Jam&output=json'
  7. );
  8. $r = multiRequest($data);
  9.  
  10. echo '<pre>';
  11. print_r($r);
  12.  
  13. ?>

В результате вы получите, что-то похожее на это:

PHP:
  1. (
  2.     [0] => {«ResultSet»:{«totalResultsAvailable»:«633»,«totalResultsReturned»:...
  3.     [1] => {«ResultSet»:{«totalResultsAvailable»:«105342»,«totalResultsReturned»:...
  4.     [2] => {«ResultSet»:{«totalResultsAvailable»:10,«totalResultsReturned»:...
  5. )

POST пример
Yahoo предлагает api к очень интересному сервису: term extraction, который анализирует большие куски текста и выдает релевантные фразы. Вот пример выполнения одновременно двух запросов к этому сервису использую POST.

PHP:
  1. <?php
  2. $data = array(array(),array());
  3.  
  4. $data[0]['url']  = 'http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction';
  5. $data[0]['post'] = array();
  6. $data[0]['post']['appid']   = 'YahooDemo';
  7. $data[0]['post']['output']  = 'php';
  8. $data[0]['post']['context'] = 'Now I lay me down to sleep,
  9.                                I pray the Lord my soul to keep;
  10.                                And if I die before I wake,
  11.                                I pray the Lord my soul to take.';
  12.  
  13. $data[1]['url']  = 'http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction';
  14. $data[1]['post'] = array();
  15. $data[1]['post']['appid']   = 'YahooDemo';
  16. $data[1]['post']['output']  = 'php';
  17. $data[1]['post']['context'] = 'Now I lay me down to sleep,
  18.                                I pray the funk will make me freak;
  19.                                If I should die before I waked,
  20.                                Allow me Lord to rock out naked.';
  21.  
  22. $r = multiRequest($data);
  23.  
  24. print_r($r);
  25. ?>

И результат:

PHP:
  1. (
  2.     [0] => a:1:{s:9:«ResultSet»;a:1:{s:6:«Result»;s:5:«sleep»;}}
  3.     [1] => a:1:{s:9:«ResultSet»;a:1:{s:6:«Result»;a:3:{i:0;s:5:«freak»;i:1;s:5:«sleep»;i:2;s:4:«funk»;}}}
  4. )

От себя добавлю: я встречался с подобной проблемой, когда занимался разработкой системы для одного литературного агентства. Система занималась тем, что разбивала текст на короткие части и отправляла их поисковой машине. Эта была своеобразная система проверки авторов на плагиат. Решил я проблему, не так элегантно как автор данной заметки, а простым выносом той части кода, что отвечала за составление и обработку результатов запроса в отдельный скрипт, который запускал из основного приложения с помощью exec (), которой передавалась команда с амперсандом на конце.

Далее

Blaze — первая открытая CMS, основанная на CodeIgniter

blaze-site.pngПару дней назад Elliot Haughin анонсировал свою новую CMS основанную на php фреймворке CodeIgniter — Blaze. Blaze распространяется под довольно либеральной лицензией: Creative Commons Attribution-No Derivative Works 2.0 UK: England & Wales License. Пока это только ранняя альфа версия, но уже готова к использованию в качестве каркаса для CI проекта. Готовы модули авторизации, создание страниц, записей блога, rss модуль. Эллиот обещает выпустить релиз через пару недель, буду ждать и возможно постою свой сдедующий проект на blaze.

Далее

CodeIgniter Framework

Последнее обновление 2.09.08

Просмотрел запросы по которым ко мне заходят на блог: часто фигурирую codeigniter про который я уже несколько раз упоминал. И решил собрать побольше информации об этом php фреймворке на одной странице, чтобы всем было удобнее. Если я что-то упустил — нестесняйтесь, добавляй комментарии.

Если кто не знает CodeIgniter — открытый фреймворк написанный на PHP для разработки полноценных веб-систем и приложений. Разработан компанией EllisLab, а также Риком Эллисом (Rick Ellis) и Полом Бурдиком (Paul Burdick).

Из его особенностей обычно выделяют:

  • Поддержка версий PHP4 и PHP5.
  • Модель MVC (Model-View-Controller).
  • Поддержка баз данных MySQL, PostgreSQL, MSSQL, SQLite, Oracle.
  • Хорошо спроектированная документация на англ. языке с примерами.
  • Очень быстр в работе. В этом смысле — эталон скорости и пример для подражания.

Ресурсы, где вы можете почерпнуть основную информацию об этом продукте:

CMS построенные на CodeIgniter:

Приложения на CodeIgniter c открытым кодом:

Руководства, статьи и заметки:

Библиотеки:

Плагины:

Хелперы:

Последнее обновление 2.09.08

Далее

Создание RSS потока в CodeIgniter

У нас (в Linux-Online) есть система управления репозиториями и системы сборки iso-образов с вебмордой на CodeIgniter'e. Естественно ведутся логи, сегодня подумал, что было бы удобно чтобы логи транслировались в RSS — ставим любой RSS ридер с поддержкой нотификаций в треи, красота. Естественно велик не стал изобретать — нашел вариант от Delek Allard'a. Изложу его на русском :)

Итак начнем с контроллера, который я назвал «feed»:

PHP:
  1. <?php
  2. class Feed extends Controller
  3. {
  4.  
  5.     function Feed()
  6.     {
  7.         parent::Controller();
  8.         $this->load->model('posts_model', '', TRUE);
  9.         $this->load->helper('xml');
  10.     }
  11.    
  12.     function index()
  13.     {
  14.         $data['encoding'] = 'utf-8';
  15.         $data['feed_name'] = 'DerekAllard.com';
  16.         $data['feed_url'] = 'http://www.derekallard.com';
  17.         $data['page_description'] = 'Code Igniter, PHP, and the World of Web Design';
  18.         $data['page_language'] = 'en-ca';
  19.         $data['creator_email'] = 'Derek Allard is at derek at derekallard dot com';
  20.         $data['posts'] = $this->posts_model->getRecentPosts();   
  21.         header(«Content-Type: application/rss+xml»);
  22.         $this->load->view('feed/rss', $data);
  23.     }
  24. }
  25. ?>

Важно заметит, что без объявления заголовка (строка #18) браузер проинтерпретировал бы вывод как обычный текст или как xml файл и предложил бы его загрузить, естественно нам такого результата не хотелось. Также в строке #17 мы обращаемся к методу getRecentPosts из модели posts_model, который содержит следующий код:

PHP:
  1. function getRecentPosts ()
  2. {
  3.         $this->db->orderby('post_date', 'desc');
  4.         $this->db->where('post_visible', 1);
  5.         $this->db->limit(10);
  6.         return $this->db->get('posts');
  7. }

Выборка с условием, что колонка 'post_visible' должна содержать 1, необходима если вы не хотите отдавать пост на публику, например если это черновик. Теперь посмотрим шаблон (view) 'rss':

PHP:
  1. <?php
  2. echo '<?xml version="1.0" encoding="utf-8"?>';
  3. ?>
  4. <rss version=«2.0»
  5.     xmlns:dc=«http://purl.org/dc/elements/1.1/»
  6.     xmlns:sy=«http://purl.org/rss/1.0/modules/syndication/»
  7.     xmlns:admin=«http://webns.net/mvcb/»
  8.     xmlns:rdf=«http://www.w3.org/1999/02/22-rdf-syntax-ns#»
  9.     xmlns:content=«http://purl.org/rss/1.0/modules/content/»>
  10.  
  11.     <channel>
  12.    
  13.     <title><?php echo $feed_name; ?></title>
  14.  
  15.     <link><?php echo $feed_url; ?></link>
  16.     <description><?php echo $page_description; ?></description>
  17.     <dc :language><?php echo $page_language; ?></dc>
  18.     <dc :creator><?php echo $creator_email; ?></dc>
  19.  
  20.     <dc :rights>Copyright <?php echo gmdate(«Y», time()); ?></dc>
  21.     <admin :generatorAgent rdf:resource=«http://www.codeigniter.com/» />
  22.  
  23.     <?php foreach($posts->result() as $entry): ?>
  24.    
  25.         <item>
  26.  
  27.           <title><?php echo xml_convert($entry->post_title); ?></title>
  28.           <link><?php echo site_url('blog/post/' . $entry->url_title) ?></link>
  29.           <guid><?php echo site_url('blog/post/' . $entry->url_title) ?></guid>
  30.  
  31.           <description><![CDATA[
  32.       <?= str_replace('/img/post_resources/', base_url() . 'img/post_resources/', $entry->post_body); ?>
  33.       ]]></description>
  34.       <pubdate><?php echo date ('r', $entry->post_date);?></pubdate>
  35.         </item>
  36.  
  37.     <?php endforeach; ?>
  38.    
  39.     </channel>
  40. </rss>

В шаблоне я использовал PHP функцию echo для вывода строки «<?xml version="1.0"?>» , т.к. интерпритатор мог воспринять «<?» и «?>» за открывающиеся и закрывающиеся тэги PHP.
И наконец строка:

PHP:
  1. <?= str_replace('/img/post_resources/', base_url() . 'img/post_resources/', $entry->post_body); ?>

которая с помощью функции замены строк str_replace преобразует относительные пути к изображению в абсолютные.

Вот так всё оказалось просто. :)

Далее