Статьи

6 CodeIgniter Hacks для мастеров

CodeIgniter — это простой и мощный фреймворк с открытым исходным кодом для PHP. Сегодня мы сделаем несколько основных «взломов» этой платформы, чтобы изменить и улучшить ее функциональность. В процессе вы получите лучшее понимание тонкостей CodeIgniter.

  1. Не рекомендуется применять эти хаки к существующему проекту. Поскольку они изменяют некоторые основные функции CodeIgniter, это может нарушить существующий код.
  2. На момент написания этой статьи CodeIgniter 1.7.2 является последней стабильной версией. Эти хаки не гарантируются для будущих (или прошлых) выпусков.
  3. Хотя CodeIgniter разработан для совместимости с PHP 4, некоторые из этих хаков не являются. Так что вам понадобится сервер с установленным PHP 5.
  4. Когда вы вносите какие-либо изменения в файлы внутри системной папки, вы должны документировать их где-нибудь для дальнейшего использования. В следующий раз, когда вы обновите CodeIgniter (хотя они не выпускают обновления очень часто), вам может понадобиться повторно применить эти изменения.

С левой стороны вы видите обычный способ загрузки модели в CodeIgniter из контроллера. После этого взлома мы сможем создавать объекты напрямую. Код чище, и ваша IDE сможет распознавать типы объектов. Это включает функции IDE, такие как автозаполнение или предварительный просмотр документации.

Есть еще два побочных эффекта этого взлома. Во-первых, вам больше не нужно расширять класс Model:

И вам больше не нужно добавлять вызов require_once перед выполнением наследования класса модели.

Все, что нам нужно сделать, это добавить функцию автозагрузчика в стиле PHP 5.

Добавьте этот код в конец system / application / config / config.php:

1
2
3
4
5
6
7
8
9
<?php
// …
 
function __autoload($class) {
    if (file_exists(APPPATH.»models/».strtolower($class).EXT)) {
        include_once(APPPATH.»models/».strtolower($class).EXT);
    }
}
?>

Если вы заинтересованы в применении этого хака для контроллеров, вы можете использовать этот код:

01
02
03
04
05
06
07
08
09
10
11
<?php
// …
 
function __autoload($class) {
    if (file_exists(APPPATH.»models/».strtolower($class).EXT)) {
        include_once(APPPATH.»models/».strtolower($class).EXT);
    } else if (file_exists(APPPATH.»controllers/».strtolower($class).EXT)) {
        include_once(APPPATH.»controllers/».strtolower($class).EXT);
    }
}
?>

Каждый раз, когда вы пытаетесь использовать класс, который не определен, эта функция __autoload вызывается первой. Он заботится о загрузке файла класса.

Как правило, вы не можете иметь одно и то же имя класса для модели и контроллера. Допустим, вы создали название модели Post:

1
2
3
4
5
class Post extends Model {
 
    // …
 
}

Теперь вы не можете иметь такой URL:

1
http://www.mysite.com/post/display/13

Причина в том, что для этого также потребуется класс Controller с именем «Post». Создание такого класса приведет к фатальной ошибке PHP.

Но с этим взломом это станет возможным. И контроллер для этого URL будет выглядеть так:

1
2
3
4
5
6
7
// application/controllers/post.php
 
class Post_controller extends Controller {
 
    // …
 
}

Обратите внимание на суффикс _controller.

Чтобы обойти эту проблему, обычно большинство людей добавляют суффикс ‘_model’ к именам классов Model (например, Post_model). Объекты модели создаются и на них ссылаются по всему приложению, поэтому может показаться немного глупым иметь все эти имена с плавающей точкой _model. Я думаю, что вместо этого лучше добавить суффикс к контроллерам, поскольку на них почти никогда не ссылаются их имена классов в вашем коде.

Сначала нам нужно расширить класс Router. Создайте этот файл: «application / library / MY_Router.php»

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
class MY_Router extends CI_Router {
    var $suffix = ‘_controller’;
 
    function MY_Router() {
        parent::CI_Router();
    }
 
    function set_class($class) {
        $this->class = $class .
    }
 
    function controller_name() {
 
        if (strstr($this->class, $this->suffix)) {
            return str_replace($this->suffix, », $this->class);
        }
        else {
            return $this->class;
        }
 
    }
}

Теперь отредактируйте строку «system / codeigniter / CodeIgniter.php» 153:

1
if ( ! file_exists(APPPATH.’controllers/’.$RTR->fetch_directory().$RTR->controller_name().EXT))

Тот же файл, строка 158:

1
include(APPPATH.’controllers/’.$RTR->fetch_directory().$RTR->controller_name().EXT);

Затем отредактируйте: «system / library / Profiler.php», строка 323:

1
$output .= «<div style=’color:#995300;font-weight:normal;padding:4px 0 4px 0′>».$this->CI->router->controller_name().»/».$this->CI->router->fetch_method().»</div>»;

Это все. Имейте в виду, что с этим хаком вы должны поставить суффикс ‘_controller’ на все имена классов вашего контроллера. Но не в именах файлов или URL.

CodeIgniter имеет хороший класс Form_validation . Он поставляется с несколькими правилами проверки:

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

С этим хаком вы сможете очень легко добавить это правило проверки в ваш обработчик отправки формы:

1
2
$this->form_validation->set_rules(‘username’, ‘Username’,
       ‘required|alpha_numeric|min_length[6]|unique[User.username]’);

Обратите внимание на последнюю часть, которая гласит «уникальное [User.username]». Это новое правило проверки называется просто «уникальным» и принимает параметр в квадратных скобках, который называется «tablename.fieldname». Поэтому он проверит столбец «username» таблицы «User», чтобы убедиться, что отправленное значение еще не существует.

Точно так же вы можете проверить наличие дубликатов электронных писем:

1
2
$this->form_validation->set_rules(’email’, ‘E-mail’,
       ‘required|valid_email|unique[User.email]’);

И ваше приложение может ответить правильными сообщениями об ошибках:

Это можно считать скорее расширением, чем взломом. Тем не менее, мы собираемся взять базовую библиотеку CodeIgniter и улучшить ее.

Создать: «application / library / MY_Form_validation.php»

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MY_Form_validation extends CI_Form_validation {
 
    function unique($value, $params) {
 
        $CI =& get_instance();
        $CI->load->database();
 
        $CI->form_validation->set_message(‘unique’,
            ‘The %s is already being used.’);
 
        list($table, $field) = explode(«.», $params, 2);
 
        $query = $CI->db->select($field)->from($table)
            ->where($field, $value)->limit(1)->get();
 
        if ($query->row()) {
            return false;
        } else {
            return true;
        }
 
    }
}

Теперь вы можете использовать уникальное правило проверки.

Как и в заголовке, наша цель — запускать приложения CodeIgniter из командной строки. Это необходимо для создания заданий cron или выполнения более интенсивных операций, чтобы у вас не было ограничений по ресурсам веб-скрипта, таких как максимальное время выполнения.

Вот как это выглядит на моей локальной машине с Windows:

Приведенный выше код будет похож на вызов этого URL:

1
http://www.mysite.com/hello/world/foo

Создайте файл «cli.php» в корне вашей папки CodeIgniter:

1
2
3
4
5
6
7
8
9
if (isset($_SERVER[‘REMOTE_ADDR’])) {
    die(‘Command Line Only!’);
}
 
set_time_limit(0);
 
$_SERVER[‘PATH_INFO’] = $_SERVER[‘REQUEST_URI’] = $argv[1];
 
require dirname(__FILE__) .

Если вы работаете в среде Linux и хотите, чтобы этот скрипт выполнялся самостоятельно, вы можете добавить его в качестве первой строки в cli.php:

1
#!/usr/bin/php

Если вы хотите, чтобы конкретный контроллер был только командной строкой, вы можете заблокировать веб-вызовы в конструкторе контроллера:

01
02
03
04
05
06
07
08
09
10
11
12
class Hello extends Controller {
 
    function __construct() {
        if (isset($_SERVER[‘REMOTE_ADDR’])) {
            die(‘Command Line Only!’);
        }
        parent::Controller();
    }
 
    // …
 
}

Doctrine — это популярный объектно-реляционный картограф для PHP. Добавив его в CodeIgniter, вы можете иметь очень мощный уровень Model в вашей структуре.

Сама установка Doctrine сама по себе не очень «хакерская», так как мы можем просто добавить ее в качестве плагина. Однако после добавления ваши классовые модели должны будут расширять базовые классы Doctrine вместо класса CodeIgniter Model. Это полностью изменит способ работы слоя модели в каркасе. Созданные вами объекты будут иметь постоянство базы данных, а также смогут иметь связь с другими объектами.

Следуй этим шагам:

  1. Создать папку: приложение / плагины
  2. Создать папку: application / plugins / doctrine
  3. Скачать Doctrine (1.2 с этой статьи)
  4. Скопируйте папку «lib» из Doctrine в: «application / plugins / doctrine»
  5. Создайте «application / plugins / doctrine_pi.php»
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// system/application/plugins/doctrine_pi.php
 
// load Doctrine library
require_once APPPATH.’/plugins/doctrine/lib/Doctrine.php’;
 
// load database configuration from CodeIgniter
require_once APPPATH.’/config/database.php’;
 
// this will allow Doctrine to load Model classes automatically
spl_autoload_register(array(‘Doctrine’, ‘autoload’));
 
// we load our database connections into Doctrine_Manager
// this loop allows us to use multiple connections later on
foreach ($db as $connection_name => $db_values) {
 
    // first we must convert to dsn format
    $dsn = $db[$connection_name][‘dbdriver’] .
        ‘://’ .
        ‘:’ .
        ‘@’ .
        ‘/’ .
 
    Doctrine_Manager::connection($dsn,$connection_name);
}
 
// CodeIgniter’s Model class needs to be loaded
require_once BASEPATH.’/libraries/Model.php’;
 
// telling Doctrine where our models are located
Doctrine::loadModels(APPPATH.’/models’);

Затем отредактируйте «application / config / autoload.php», чтобы автоматически загрузить этот плагин Doctrine

1
$autoload[‘plugin’] = array(‘doctrine’);

Также убедитесь, что у вас есть конфигурация базы данных в «application / config / database.php».

Это все. Теперь вы можете создавать Doctrine-модели в вашем приложении CodeIgniter. Прочитайте мои учебники по этой теме для получения дополнительной информации.

Этот хак позволит вам запускать несколько сайтов из одной установки CodeIgniter. Каждый веб-сайт будет иметь свою собственную папку приложений, но все они будут использовать одну и ту же системную папку.

Установите CodeIgniter в любом месте на сервере. Это не должно быть в папке сайта. Затем выньте папку приложения из системной папки. И сделайте дополнительные копии, как показано на рисунке выше, для каждого веб-сайта, который вы хотите запустить. Вы можете разместить эти папки приложений в любом месте, например, под каждой отдельной папкой сайта.

Теперь скопируйте файл index.php в корень каждой папки сайта и отредактируйте его следующим образом:

В строке 26 укажите полный путь к системной папке:

1
$system_folder = dirname(__FILE__) .

В строке 43 укажите полный путь к папке приложения:

1
$application_folder = dirname(__FILE__) .

Теперь вы можете иметь независимые веб-сайты, использующие отдельные папки приложений, но совместно использующие одну и ту же системную папку.

В Руководстве пользователя CodeIgniter есть аналогичная реализация, которую вы также можете прочитать.

При использовании библиотеки загрузки в CodeIgniter вы должны указать, какие типы файлов разрешены.

1
2
3
$this->load->library(‘upload’);
 
$this->upload->set_allowed_types(‘jpg|jpeg|gif|png|zip’);

Если вы не укажете какие-либо типы файлов, вы получите сообщение об ошибке от CodeIgniter: «Вы не указали разрешенные типы файлов».

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

1
2
3
$this->load->library(‘upload’);
 
$this->upload->set_allowed_types(‘*’);

Для этого хака мы собираемся изменить поведение класса Upload.

Создать файл: приложение / библиотеки / My_Upload.php

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class MY_Upload extends CI_Upload {
 
    function is_allowed_filetype() {
 
        if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types))
        {
            $this->set_error(‘upload_no_file_types’);
            return FALSE;
        }
 
        if (in_array(«*», $this->allowed_types))
        {
            return TRUE;
        }
 
        $image_types = array(‘gif’, ‘jpg’, ‘jpeg’, ‘png’, ‘jpe’);
 
        foreach ($this->allowed_types as $val)
        {
            $mime = $this->mimes_types(strtolower($val));
 
            // Images get some additional checks
            if (in_array($val, $image_types))
            {
                if (getimagesize($this->file_temp) === FALSE)
                {
                    return FALSE;
                }
            }
 
            if (is_array($mime))
            {
                if (in_array($this->file_type, $mime, TRUE))
                {
                    return TRUE;
                }
            }
            else
            {
                if ($mime == $this->file_type)
                {
                    return TRUE;
                }
            }
        }
 
        return FALSE;
 
    }
 
}

Я надеюсь, что некоторые из них полезны для вас. Если нет, их все еще интересно узнать, и они могут помочь вам узнать больше о внутренней работе фреймворка и некоторых основных функциях языка PHP.

Если вы знаете какие-либо другие интересные хаки или модификации, сообщите нам об этом в комментариях. Спасибо!

  • Подпишитесь на нас в Твиттере или подпишитесь на ленту Nettuts + RSS для получения лучших учебных материалов по веб-разработке. готов

Готовы поднять свои навыки на новый уровень и начать зарабатывать на своих скриптах и ​​компонентах? Проверьте наш родной рынок, CodeCanyon .

CodeCanyon