<?php
/* SVN FILE: $Id: plugin.php 564 2008-06-07 14:40:06Z bb_yujiro $ */
/**
 * Model_Manip Controller
 *
 * PHP versions 5
 *
 *      Hitsuji : Social Network Service <http://rakuto.net/rktSNS/>
 *      Copyright (c) 2007 Yujiro Takahashi
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @filesource
 * @package         Hitsuji
 * @copyright       Copyright (c) 2007 Yujiro Takahashi
 * @link            http://rakuto.net/
 * @author          Yujiro Takahashi <yujiro@rakuto.net>
 * @version         $Revision: 564 $
 * @modifiedby      $LastChangedBy: bb_yujiro $
 * @lastmodified    $Date: 2008-06-07 23:40:06 +0900 (土, 07 6 2008) $
 * @license         http://opensource.org/licenses/mit-license.php The MIT License
 */

/**
 * Controllerクラス
 *
 * @category        Hitsuji : Controller
 * @package         Hitsuji
 * @copyright       Copyright (c) 2007 Yujiro Takahashi
 * @link            http://rakuto.net/rktSNS/
 * @author          Yujiro Takahashi <yujiro@rakuto.net>
 * @version         $Revision: 564 $
 * @modifiedby      $LastChangedBy: bb_yujiro $
 * @lastmodified    $Date: 2008-06-07 23:40:06 +0900 (土, 07 6 2008) $
 * @license         http://opensource.org/licenses/mit-license.php The MIT License
 */
class Controller extends Admin_Controller 
{
    /**
     * 使用モデル名
     * @var array
     */
    public $models = array(
        'manip'=> array(
        ),
        'view'=> array(
        ),            
    );

    /**
     * des_theme モデルオブジェクト
     * @var object 
     */
    public $des_theme = null;

    /**
     * プラグイン
     * @var string
     */
    protected $plugins = null;

    /**
     * リソースファイル
     * @var string
     */
    private $_resource = '';

    /**
     * 変数の初期化
     *
     * @abstract
     * @access protected
     * @return void
     */
    protected function initValue()
    {
        $this->objvew->setTemplate('sidebar_tpl', 'common/menu/admin/site.tpl');
    }

    /**
     * 実行処理
     *
     * @access public
     * @return void
     **/
    protected function action()
    {
        $dirs = explode('_', $this->key);
        $this->dir = PLUGIN_DIR.$dirs[0].DS.$dirs[1].DS;
        if (file_exists(PLUGIN_DIR.$dirs[0].DS.'packages.php')){
            include PLUGIN_DIR.$dirs[0].DS.'packages.php';
        }
        $info = empty($GLOBALS['INFO_PLUGIN'][$this->key])? array():$GLOBALS['INFO_PLUGIN'][$this->key];
        $this->objvew->assign('plugin', $info);

        /* インストール処理 */
        $result = false;
        if ($this->checked_nonce){
            /* テーブル作成 */
            if (file_exists($this->dir.'resource'.DS)){
                $result = $this->_copyFile($this->dir.'resource'.DS);
            }

            /* テーブル作成 */
            if (file_exists($this->dir.'sqls'.DS.'create.sql')){
                $this->_crateQuery();
            }
        }

        /* リソースファイルの表示 */
        if (file_exists($this->dir.'resource'.DS)){
            $this->_echoFile($this->dir.'resource'.DS);
        }

        /* テーブル表示の表示 */
        if (file_exists($this->dir.'sqls'.DS.'create.sql')){
            $this->_checkTable();
        }
        

        $this->objvew->assign('complete', $result);
        $this->objvew->assign('resource', $this->_resource);
    }


    /**
     * 入力条件の設定
     *
     * @access protected
     * @return string   絞込み句
     **/
    protected function setCondition()
    {
        $this->conditions = array (
            'key'=> array(
                'type'=>     'string',
                'option'=>   array(),
                'required'=> true,
                'pic_up'=>   'PathArgs'
            ),
        );
    }

    /**
     * リソースファイル表示用
     *
     * @access public
     * @param string $dir
     * @return void
     */
    private function _echoFile($dir, $indent='')
    {
        $resource = opendir($dir);
        while ($row = readdir($resource)) {
            if ($row == '.' || $row == '..') {
                continue;
            }
            $filename = $dir.$row;
            if (is_dir($filename)){
                $pos = strrpos($filename, DS);
                $this->_resource .= $indent . '<img src="'.BASE_URL.'resource/img/icons/folder.gif"'.
                                    ' width="16" height="16" align="absmiddle" alt="&gt;" />&nbsp;'.
                                    substr($filename, $pos+1)."/\r\n";
                $this->_echoFile($filename.DS, $indent."\t");
            } else {
                $pos = strrpos($dir, 'resource');
                $src = substr($dir, $pos + 9);

                $icon = file_exists(RESOURCE_DIR.$src.$row) ?'accept':'cross';
                $this->_resource .= $indent . '<img src="'.BASE_URL.'resource/img/icons/'.
                                    $icon.'.gif" width="16" height="16" align="absmiddle" alt="&gt;" />&nbsp;'.
                                    basename($filename)."\r\n";
            }
        }
        closedir($resource);
    }

    /**
     * リソースファイル表示用
     *
     * @access public
     * @param string $dir
     * @return void
     */
    private function _copyFile($dir)
    {
        $resource = opendir($dir);
        while ($row = readdir($resource)) {
            if ($row == '.' || $row == '..') {
                continue;
            }
            $filename = $dir.$row;
            if (is_dir($filename)){
                $this->_copyFile($filename.DS);
            } else {
                $pos = strrpos($dir, 'resource');
                $src = substr($dir, $pos + 9);

                /* ディレクトリ判定 */
                if (!file_exists(RESOURCE_DIR.$src)){
                    mkdir(RESOURCE_DIR.$src, 0755, true);
                }
                copy ($filename, RESOURCE_DIR.$src.$row);
            }
        }
        closedir($resource);
    }
    /**************************************************/

    /********************************************************************
     **                        テーブル作成                            **
     ********************************************************************/
    /**
     * テーブルの作成
     *
     * @access public
     * @return void
     */
    private function _checkTable()
    {
        $query = file_get_contents($this->dir.'sqls'.DS.'create.sql');
        $queries = $this->_explodeQuery($query);
        
        $tables = array();

        foreach ($queries as $query){
            $matches = array();
            preg_match('/CREATE TABLE `([\w\_]+)`/', $query, $matches);
            $table = $matches[1];
            try {
                $stmt = $this->objdb->prepare('SELECT * FROM '.$table.' LIMIT 1');
                $stmt->execute(); 

                $created = true;
            } catch (PDOException $exception){
                $created = false;
            }

            $tables[$table] = array(
                'table'=>   $table,
                'created'=> $created,
            );

        } // foreach ($queries as $query)

        $this->objvew->assign('tables', $tables);
    }

    /**
     * テーブルの作成
     *
     * @access public
     * @return void
     */
    private function _crateQuery()
    {
        $method = '_'.DB_DRIVER.'Query';
        if (USE_SET_NAMES && DB_DRIVER == 'mysql'){
            $method = '_defaultQuery';
        }
        $func = array(&$this, $method);

        $query = file_get_contents($this->dir.'sqls'.DS.'create.sql');
        $queries = $this->_explodeQuery($query);

        $result = true;
        try {
            foreach ($queries as $query){
                call_user_func($func, $query);
            } // foreach ($queries as $query)
        } catch (PDOException $exception){
            error_log('-----------  '.date('Y-m-d H:i:s')."  --------------\r\n", 3, ERROR_LOG_FILE);
            error_log($_SERVER['REQUEST_URI']."\r\n", 3, ERROR_LOG_FILE);
            error_log($exception->getMessage()."\r\n", 3, ERROR_LOG_FILE);
            error_log($exception->getTraceAsString()."\r\n", 3, ERROR_LOG_FILE);

            $result = false;
        }
        return $result;
    }

    /**
     * SQLクエリを解析し配列を返す
     *
     * @access public
     * @param string $query クエリ文字列
     * @return array 解析結果の配列
     */
    private function _explodeQuery($query)
    {
        $manips = 'CREATE|DROP|INSERT|UPDATE|DELETE|'.
                  'ROLLBACK|COPY|VACUUM|REPLACE|'.
                  'ATTACH|DETACH|CONFLICT';
        $query = preg_replace('/--.+\n/i', '', $query);
        $query = preg_replace('/\/\*.+\*\//is', '', $query);
        $query = preg_replace('/\\\"/i', '%dqt%', $query);
        $func = array('RKT_DB','__remove_semicolon');
        //$query = preg_replace_callback('/"\s+.+"/is', $func, $query);

        $queries = explode(';', $query);
        $is_trigger = false;
        $result = array();
        $count = count($queries);
    
        for ($row=0; $row<$count; $row++){
            $query = trim($queries[$row]);
            if ($is_trigger){       // トリガークエリ
                if (preg_match('/END/i', $query)){
                    $trigger .= $query.';';
                    $is_trigger = false;
                    $trigger = preg_replace('/(%dqt%)/i', '\"', $trigger);
                    $result[] = preg_replace('/%semi%/i', ';', $trigger);
                } else {
                    $trigger .= $query.';';
                }
            } else {                // 通常のクエリ
                if (preg_match('/CREATE TRIGGER/i', $query)){
                    $is_trigger = true;
                    $trigger = $query.';';
                } else if (!preg_match('/^(BEGIN|END|COMMIT)\s/i', $query)
                    && preg_match('/'.$manips.'/i', $query)){
                    $temp = preg_replace('/(%dqt%)/i', '\"', $query);
                    $result[] = preg_replace('/%semi%/i', ';', $temp);
                }
            } // if ($is_trigger)
        } // for ($row=0; $row<$count; $row++)

        return ($result);
    }

    /**
     * MySQL4.1以上用
     *
     * @access public
     * @param string $query クエリ文字列
     * @return boolean
     */
    private function _defaultQuery($query)
    {
        $this->objdb->exec($query);
    }

    /**
     * MySQL4.1以下用
     *
     * @access public
     * @param string $query クエリ文字列
     * @return boolean
     */
    private function _mysqlQuery($query)
    {
        $query = str_replace(' default CURRENT_TIMESTAMP', '', $query);
        $query = str_replace('on update CURRENT_TIMESTAMP', '', $query);
        $query = str_replace(' DEFAULT CHARSET=utf8', '', $query);

        $this->objdb->exec($query);
    }

    /**
     * PostgreSQL用
     *
     * @access public
     * @param string $query クエリ文字列
     * @return boolean
     */
    private function _pgsqlQuery($query)
    {
        $matches = array();
        preg_match('/CREATE TABLE `([\w\_]+)`/', $query, $matches);
        $table = $matches[1];

        $pos = strrpos($query, 'auto_increment');
        if ($pos !== false) {
            $sequence = str_replace(DB_PREFIX, 'seq_', $table);
            $this->objdb->exec('CREATE SEQUENCE '.$sequence.' start 1 increment 1 maxvalue 9223372036854775807 minvalue 1 cache 1');

            $query = str_replace('NOT NULL auto_increment',
                     "DEFAULT nextval('".$sequence."'::text) NOT NULL", $query);
            $query = str_replace(' AUTO_INCREMENT=1', '', $query);
        }
        $query = str_replace('`'.$table.'`', $table, $query);
        $query = str_replace('ENGINE=MyISAM DEFAULT CHARSET=utf8', '', $query);
        $query = str_replace('`', '"', $query);

        $query = str_replace('int(11)', 'integer', $query);
        $query = str_replace(' unsigned', '', $query);
        $query = str_replace('mediumblob', 'bytea', $query);
        $query = str_replace('blob', 'bytea', $query);
        $query = str_replace('timestamp', 'timestamp without time zone', $query);
        $query = str_replace('datetime', 'timestamp without time zone', $query);
        $query = str_replace(" default '0000-00-00 00:00:00'", '', $query);
        $query = str_replace(" default '0000-00-00'", '', $query);
        $query = str_replace('on update CURRENT_TIMESTAMP', '', $query);
        $query = preg_replace("/default '(\d)'/", 'DEFAULT \1', $query);
        $query = preg_replace('/UNIQUE KEY "[\w_]+"/', 'UNIQUE', $query);

        /* Index用処理 */
        $line = explode("\r\n", $query);
        $queries = array();
        $index = array();
        $count = 1;
        foreach ($line as $row){
            $matches = array();
            if (preg_match('/  KEY "[\w_]+" \(("[\w_,"]+")\)/', $row, $matches)){
                $indexname = str_replace(DB_PREFIX, 'key_', $table).'_'.$count;
                $index[] = 'CREATE INDEX '.$indexname.' ON '.$table.' ('.$matches[1].')';
                $row = preg_replace('/  KEY "([\w_]+)" \("[\w_,"]+"\)/', '', $row);
                $count++;
            } else {
                $queries[] = $row;
            }
        }
        $row = count($queries) -2;
        $queries[$row] = str_replace('),', ')', $queries[$row] );
        $query = implode("\r\n", $queries);
        $this->objdb->exec($query);

        foreach ($index as $query){
            $this->objdb->exec($query);
        }
    }

    /**
     * SQLite用
     *
     * @access public
     * @param string $query クエリ文字列
     * @return boolean
     */
    private function _sqliteQuery($query)
    {
        $matches = array();
        preg_match('/CREATE TABLE `([\w\_]+)`/', $query, $matches);
        $table = $matches[1];

        $query = str_replace('`', "'", $query);
        $query = str_replace(' AUTO_INCREMENT=1', '', $query);
        $query = str_replace('ENGINE=MyISAM DEFAULT CHARSET=utf8', '', $query);

        $query = str_replace(' auto_increment', '', $query);
        $query = str_replace('int(11)', 'integer', $query);
        $query = str_replace(' unsigned', '', $query);
        $query = str_replace('mediumblob', 'blob', $query);
        $query = str_replace('datetime', 'timestamp', $query);
        $query = str_replace('on update CURRENT_TIMESTAMP', '', $query);

        $query = preg_replace("/UNIQUE KEY '[\w_]+'/", 'UNIQUE', $query);

        /* Index用処理 */
        $line = explode("\r\n", $query);
        $queries = array();
        $index = array();
        $count = 1;
        foreach ($line as $row){
            $matches = array();
            if (preg_match("/  KEY '[\w_]+' \(('[\w_,']+')\)/", $row, $matches)){
                $indexname = str_replace(DB_PREFIX, 'key_', $table).'_'.$count;
                $index[] = 'CREATE INDEX '.$indexname.' ON '.$table.' ('.$matches[1].')';
                $row = preg_replace("/  KEY '[\w_]+' \('[\w_,']+'\)/", '', $row);
                $count++;
            } else {
                $queries[] = $row;
            }
        }
        $row = count($queries) -2;
        $queries[$row] = str_replace('),', ')', $queries[$row] );
        $query = implode("\r\n", $queries);
        $this->objdb->exec($query);

        foreach ($index as $query){
            $this->objdb->exec($query);
        }
    }
} // class Controller
?>
