Project

General

Profile

1
<?php
2

    
3
/**
4
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20
/**
21
 * SqlImport.php
22
 *
23
 * @category     Core
24
 * @package      Core_Database
25
 * @copyright    Manuela v.d.Decken <manuela@isteam.de>
26
 * @author       Manuela v.d.Decken <manuela@isteam.de>
27
 * @license      http://www.gnu.org/licenses/gpl.html   GPL License
28
 * @version      0.0.1
29
 * @revision     $Revision: 2070 $
30
 * @lastmodified $Date: 2014-01-03 02:21:42 +0100 (Fr, 03 Jan 2014) $
31
 * @since        File available since 30.11.2014
32
 * @description  can handle different actions with SQL-Import files
33
 */
34
class SqlImport {
35

    
36
/** WbDatabase object */
37
    protected $oDb          = null;
38
/** valide structure file to use for import */
39
    protected $sStructFile  = '';
40
/** valide TablePrefix to use for import */
41
    protected $sTablePrefix = '';
42
/** default Collation to use for import of chars/text */
43
    protected $sCollation   = 'utf8_unicode_ci';
44
/** default engine for tables */
45
    protected $sEngine      = 'MyISAM';
46
/** collected error messages */
47
    protected $aErrMsg      = array();
48
/** possible actions for doImport() */
49
    protected $aActions     = array(
50
        'uninstall',
51
        'install',
52
        'upgrade'
53
    );
54
/** collected additional replacements pairs */
55
    protected $aReplacements = array('key'=>array(), 'value'=>array());
56
/** possible engines to use */
57
    protected $aEngineTypesAvail = array(
58
        'memory'     => 'MEMORY',
59
        'myisam'     => 'MyISAM',
60
        'innodb'     => 'InnoDB',
61
        'archive'    => 'ARCHIVE'
62
    );
63
/** SQL objects witch can be handled */
64
    protected $aAvailSqlObjects = array(
65
        'TABLE',
66
        'VIEW',
67
        'INDEX',
68
        'PROCEDURE',
69
        'FUNCTION',
70
        'TRIGGER',
71
        'EVENT'
72
    );
73
/**
74
 * Constructor
75
 * @param WbDatabase $oDb
76
 * @param string $sStructFile
77
 */
78
    public function __construct(WbDatabase $oDb, $sStructFile)
79
    {
80
        $this->oDb = $oDb;
81
        $this->sTablePrefix = $oDb->TablePrefix;
82
        if (file_exists($sStructFile)) {
83
            $this->sStructFile = str_replace('\\', '/', $sStructFile);
84
        } else {
85
            $this->sStructFile = '';
86
            $this->aErrMsg[] = 'file with structure not available! ['.$sStructFile.']';
87
        }
88
    }
89
/**
90
 * Add Key-Value pairs for additional placeholders
91
 * @param string $sKey
92
 * @param mixed $sValue
93
 */
94
    public function addReplacement($sKey, $sValue = '')
95
    {
96
        $sKey = strtoupper(preg_replace('/([a-z0-9])([A-Z])/', '\1_\2', ltrim($sKey, 'a..z')));
97
        $this->aReplacements['key'][]  = '/\{'.$sKey.'\}/';
98
        $this->aReplacements['value'][] = $sValue;
99
    }
100
/**
101
 * define another collation then default utf8_unicode_ci
102
 * @param string $sCollation
103
 * @return boolean
104
 */
105
    public function setDefaultCollation($sCollation = 'utf8_unicode_ci')
106
    {
107
        $bRetval = false;
108
        // test if selected collation is available on current server.
109
        $sql = 'SHOW COLLATION LIKE \''.$this->oDb->escapeString(addcslashes($sCollation, '_%')).'\'';
110
        if (($oAvailCollations = $this->oDb->doQuery($sql))) {
111
            if (($oAvailCollations->numRows())) {
112
                //use new collation
113
                $this->sCollation = $sCollation;
114
                $bRetval = true;
115
            }
116
        }
117
        return $bRetval;
118
    }
119
/**
120
 * define another prefix then 'MyISAM'
121
 * @param string $sEngine
122
 * @return boolean
123
 */
124
    public function setDefaultEngine($sEngine ='MyISAM')
125
    {
126
        $bRetval = false;
127
        if (isset($this->aEngineTypesAvail[strtolower($sEngine)])) {
128
            // use new engine
129
            $this->sEngine = $this->aEngineTypesAvail[strtolower($sEngine)];
130
            $bRetval = true;
131
        }
132
        return $bRetval;
133
    }
134
/**
135
 * define another prefix then default in Wbdatabase
136
 * @param string $sTablePrefix
137
 * @return boolean
138
 */
139
    public function setTablePrefix($sTablePrefix = '')
140
    {
141
        $bRetval = false;
142
        if (
143
        // Prefix must be empty or matching allowed table names
144
            $sTablePrefix == '' ||
145
            preg_match('/^[a-z][a-z0-9_]*$/i', $sTablePrefix)
146
        ) {
147
            // use new TablePrefix
148
            $this->sTablePrefix = $sTablePrefix;
149
            $bRetval = true;
150
        }
151
        return $bRetval;
152
    }
153
/**
154
 * Start and execute the import
155
 * @param string $sAction
156
 * @return boolean
157
 */
158
    public function doImport($sAction)
159
    {
160
        if (! $this->sStructFile) {
161
        // no file found so ignore import method
162
            return true;
163
        }
164
        if (! is_readable($this->sStructFile)) {
165
        // file fond but it's not readable
166
            $this->aErrMsg[] = 'unable to read file ['.$this->sStructFile.']';
167
            return false;
168
        }
169
        $sAction = strtolower(
170
            preg_replace(
171
                '/^.*?('.implode('|', $this->aActions).')(\.php)?$/i',
172
                '$1',
173
                $sAction
174
            )
175
        );
176
        if ($this->importSql(($sAction == '' ? 'install' : $sAction))) {
177
            return true;
178
        } else {
179
            $this->aErrMsg[] = $this->oDb->getError();
180
            return false;
181
        }
182
    }
183
/**
184
 * return errorstrings, concatet by LF
185
 * @return string
186
 */
187
    public function getError()
188
    {
189
        return implode(PHP_EOL, $this->aErrMsg);
190
    }
191
/**
192
 * Import an SQl-Dumpfile witch can include unlimited additional placeholders for values
193
 * @param string $sAction 'install' || 'uninstall' || 'upgrade'
194
 * @return bool  false on error
195
 */
196
    protected function importSql($sAction = 'install')
197
    {
198
        $retval = true;
199
        $this->error = '';
200
        // sanitize arguments
201
        $aTmp = preg_split('/_/', $this->sCollation, null, PREG_SPLIT_NO_EMPTY);
202
        $sCharset = $aTmp[0];
203
        // get from addReplacements
204
        $aSearch  = $this->aReplacements['key'];
205
        /* ***  ATTENTION:: Do Not Change The Order Of Search-Replace Statements !! *** */
206
        // define basic array of searches
207
        $aSearch[] = '/\{TABLE_PREFIX\}/';                                        /* step 0 */
208
        $aSearch[] = '/\{FIELD_CHARSET\}/';                                       /* step 1 */
209
        $aSearch[] = '/\{FIELD_COLLATION\}/';                                     /* step 2 */
210
        $aSearch[] = '/\{TABLE_ENGINE\}/';                                        /* step 3 */
211
        $aSearch[] = '/\{TABLE_ENGINE=([a-zA-Z_0-9]*)\}/';                        /* step 4 */
212
        $aSearch[] = '/\{CHARSET\}/';                                             /* step 5 */
213
        $aSearch[] = '/\{COLLATION\}/';                                           /* step 6 */
214
        // get from addReplacements
215
        $aReplace = $this->aReplacements['value'];
216
        // define basic array of replacements
217
        $aReplace[] = $this->sTablePrefix;                                        /* step 0 */
218
        $aReplace[] = ' CHARACTER SET {CHARSET}';                                 /* step 1 */
219
        $aReplace[] = ' COLLATE {COLLATION}';                                     /* step 2 */
220
        $aReplace[] = ' {TABLE_ENGINE='.$this->sEngine.'}';                       /* step 3 */
221
        $aReplace[] = ' ENGINE=$1 DEFAULT CHARSET={CHARSET} COLLATE={COLLATION}'; /* step 4 */
222
        $aReplace[] = $sCharset;                                                  /* step 5 */
223
        $aReplace[] = $this->sCollation;                                          /* step 6 */
224

    
225
        $sql = ''; // buffer for statements
226
        $aSql = file($this->sStructFile, FILE_SKIP_EMPTY_LINES|FILE_IGNORE_NEW_LINES);
227
        //  remove possible ByteOrderMark
228
        $aSql[0] = preg_replace('/^[\xAA-\xFF]{3}/', '', $aSql[0]);
229
    // iterate file line by line
230
        while (sizeof($aSql) > 0) {
231
            // remove trailing and leading whitespaces
232
            $sSqlLine = trim(array_shift($aSql));
233
            // skip line if it's a comment
234
            if (preg_match('/^--/', $sSqlLine)) { continue; }
235
            // attach line to buffer
236
            $sql = $sql.' '.$sSqlLine;
237
            // detect end of statement
238
            if ((substr($sql,-1,1) == ';')) {
239
                // replace placeholders in statement
240
                $sql = trim(preg_replace($aSearch, $aReplace, $sql));
241
                $sAvailSqlObjects = implode('|', $this->aAvailSqlObjects);
242
                switch ($sAction) {
243
                    case 'uninstall': // execute DROP - skip CREATE
244
                        if (preg_match('/^\s*CREATE ('.$sAvailSqlObjects.') /si', $sql)) {
245
                            $sql = ''; // clear buffer
246
                            continue 2; // read next statement
247
                        }
248
                        break;
249
                    case 'upgrade': // skip DROP; execute CREATE
250
                        if (preg_match('/^\s*DROP ('.$sAvailSqlObjects.') /si', $sql)) {
251
                            $sql = ''; // clear buffer
252
                            continue 2; // read next statement
253
                        }
254
                        break;
255
                    default: // install:  execute DROP; execute CREATE
256
                        break;
257
                }
258
                if (!$this->oDb->doQuery($sql)) {
259
                    $retval = false;
260
                    $this->aErrMsg[] = $this->oDb->getError();
261
                    unset($aSql);
262
                    break;
263
                }
264
                $sql = ''; // clear buffer
265
            }
266
        }
267
        return $retval;
268
    } // end of function importSql()
269

    
270
}
(10-10/38)