codeigniter - pyrocms intercept and modify all que

2019-07-07 08:27发布

问题:

Is there a way to catch all queries and modify them before being sent to the db outside of modifying DB_active_record.php? This would be ideal, though I'm not averse to modifying this file if it's the only option.

I could just call this stuff from the models, but would feel better if this was something that was done in the background so as not to leave room for forgetting when and where it's happening; it'd be best to have it done in the background.

I'm using a library to encrypt query data. In the lib, I'm checking for certain keys to not encrypt, so it's not just a matter of encrypting all data, but some data in each query.

For example, modifying insert() like so:

function insert($table = '', $set = NULL)
{
    if ( ! is_null($set))
    {
        $this->CI =& get_instance();
        $this->CI->load->library('my_encrypt');
        $set = $this->CI->my_encrypt->encrypt_query($set);
        $this->set($set);
    }

works correctly to encrypt the data before sending to the db. However, this does nothing for updates/sets nor decryption.

Is there a way to set up an intermediary something or other that acts as a go-between between models and active record where I could encrypt and decrypt the relevant data before sending it on to AR or back to the model?

Thanks.


UPDATE:

So following the guide below, I was able to get this working. I'm using pyroCMS (ver. 1.3.2 community; CI version 2.0.2) which had already done some of the legwork.

Heres what I did.

system/cms/core/MY_Loader.php extends MX_loader which extends CI_Loader; so MX_Loader is what needs to be modified.


system/cms/libraries/MX/Loader.php

change public function database() to:

public function database($params = '', $return = FALSE, $active_record = NULL) {
    log_message('debug', 'db loader from MX/Loader');

    // Grab the super object
    $CI =& get_instance();

    // Do we even need to load the database class?
    if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db)) {
        return FALSE;
    }

    require_once(BASEPATH.'database/DB'.EXT);

    // Load the DB class
    $db =& DB($params, $active_record);

    //get the driver name, set its path and load er up
    $my_driver = config_item('subclass_prefix').'DB_'.$db->dbdriver.'_driver';
    $my_driver_file = APPPATH.'core/'.$my_driver.EXT;

    if (file_exists($my_driver_file)) {
        require_once($my_driver_file);
        $db = new $my_driver(get_object_vars($db));
    }

    if ($return === TRUE) {
        return $db;
    }

    CI::$APP->db = DB($params, $active_record);
    return CI::$APP->db;
}

The important difference here from the article linked in the accepted answer is the setting of the db vars as pyro does it differently from regular CI.

Then in system/cms/core add the customized driver file MY_DB_mysql_driver.php. This will then be loaded and these methods will be available in all models. Also, methods in here using the same name as in DB_active_rec.php will take precedence. e.g. adding an insert method in MY_DB_mysql_driver.php will override the insert method in DB_active_rec.php.

回答1:

By default you cannot extend the active record class. You can however, extend the active record class after extending the loader class database call to allow it:

Instructions & code here: http://www.simonemms.com/code/extending-the-codeigniter-database-class/



回答2:

You can't extend the active record class without modifying the core (which really sucks). So, you have a couple of options:

  • Create a base model that implements the functionality you want, and extend that with your various models (this way you only do it once)
  • Add the functionality to each model (not DRY)
  • Overwrite the core files (not ideal) - it's only a few lines of code: http://robotslacker.com/2011/05/extending-codeigniters-active-record-class/