OSDN Git Service

[NEW] データベースをハンドルする新しいDBクラスを追加。関連する修正を反映。
[nucleus-jp/nucleus-next.git] / nucleus / libs / sql / MYSQLPDO.php
1 <?php\r
2 /*\r
3  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)\r
4  * Copyright (C) 2012 The Nucleus Group\r
5  *\r
6  * This program is free software; you can redistribute it and/or\r
7  * modify it under the terms of the GNU General Public License\r
8  * as published by the Free Software Foundation; either version 2\r
9  * of the License, or (at your option) any later version.\r
10  * (see nucleus/documentation/index.html#license for more info)\r
11  */\r
12 /**\r
13  * @license http://nucleuscms.org/license.txt GNU General Public License\r
14  * @copyright Copyright (C) 2012 The Nucleus Group\r
15  * @version $Id$\r
16  */\r
17 \r
18 if ( !class_exists('PDO') )\r
19 {\r
20 \r
21         /**\r
22          * Dummy constant of the PDO class\r
23          */\r
24         class PDO\r
25         {\r
26                 /* constant values */\r
27                 const PARAM_NULL = 0;\r
28                 const PARAM_INT = 1;\r
29                 const PARAM_STR = 2;\r
30                 const PARAM_LOB = 3;\r
31                 const PARAM_STMT = 4;\r
32                 const PARAM_BOOL = 5;\r
33                 const PARAM_INPUT_OUTPUT = 128; // orignal is undefined.\r
34                 const FETCH_LAZY = 1;\r
35                 const FETCH_ASSOC = 2;\r
36                 const FETCH_NUM = 3;\r
37                 const FETCH_BOTH = 4;\r
38                 const FETCH_OBJ = 5;\r
39                 const FETCH_BOUND = 6;\r
40                 const FETCH_COLUMN = 7;\r
41                 const FETCH_CLASS = 8;\r
42                 const FETCH_INTO = 9;\r
43                 const FETCH_FUNC = 10;\r
44                 const FETCH_NAMED = 11;\r
45                 const FETCH_KEY_PAIR = 12;\r
46                 const FETCH_GROUP = 65536;\r
47                 const FETCH_UNIQUE = 196608;\r
48                 const FETCH_CLASSTYPE = 262144;\r
49                 const FETCH_SERIALIZE = 524288;\r
50                 const FETCH_PROPS_LATE = 1048576;\r
51                 const ATTR_AUTOCOMMIT = 0;\r
52                 const ATTR_PREFETCH = 1;\r
53                 const ATTR_TIMEOUT = 2;\r
54                 const ATTR_ERRMODE = 3;\r
55                 const ATTR_SERVER_VERSION = 4;\r
56                 const ATTR_CLIENT_VERSION = 5;\r
57                 const ATTR_SERVER_INFO = 6;\r
58                 const ATTR_CONNECTION_STATUS = 7;\r
59                 const ATTR_CASE = 8;\r
60                 const ATTR_CURSOR_NAME = 9;\r
61                 const ATTR_CURSOR = 10;\r
62                 const ATTR_ORACLE_NULLS = 11;\r
63                 const ATTR_PERSISTENT = 12;\r
64                 const ATTR_STATEMENT_CLASS = 13;\r
65                 const ATTR_FETCH_TABLE_NAMES = 14;\r
66                 const ATTR_FETCH_CATALOG_NAMES = 15;\r
67                 const ATTR_DRIVER_NAME = 16;\r
68                 const ATTR_STRINGIFY_FETCHES = 17;\r
69                 const ATTR_MAX_COLUMN_LEN = 18;\r
70                 const ATTR_DEFAULT_FETCH_MODE = 19;\r
71                 const ATTR_EMULATE_PREPARES = 20;\r
72                 const ERRMODE_SILENT = 0;\r
73                 const ERRMODE_WARNING = 1;\r
74                 const ERRMODE_EXCEPTION = 2;\r
75                 const CASE_NATURAL = 0;\r
76                 const CASE_UPPER = 1;\r
77                 const CASE_LOWER = 2;\r
78                 const NULL_NATURAL = 0;\r
79                 const NULL_EMPTY_STRING = 1;\r
80                 const NULL_TO_STRING = 2;\r
81                 const FETCH_ORI_NEXT = 0;\r
82                 const FETCH_ORI_PRIOR = 1;\r
83                 const FETCH_ORI_FIRST = 2;\r
84                 const FETCH_ORI_LAST = 3;\r
85                 const FETCH_ORI_ABS = 4;\r
86                 const FETCH_ORI_REL = 5;\r
87                 const CURSOR_FWDONLY = 0;\r
88                 const CURSOR_SCROLL = 1;\r
89                 // from here orignal is undefined.\r
90                 const ERR_CANT_MAP = 0;\r
91                 const ERR_SYNTAX = 0;\r
92                 const ERR_CONSTRAINT = 0;\r
93                 const ERR_NOT_FOUND = 0;\r
94                 const ERR_ALREADY_EXISTS = 0;\r
95                 const ERR_NOT_IMPLEMENTED = 0;\r
96                 const ERR_MISMATCH = 0;\r
97                 const ERR_TRUNCATED = 0;\r
98                 const ERR_DISCONNECTED = 0;\r
99                 const ERR_NO_PERM = 0;\r
100                 // so far\r
101                 const ERR_NONE = '00000';\r
102                 const PARAM_EVT_ALLOC = 0;\r
103                 const PARAM_EVT_FREE = 1;\r
104                 const PARAM_EVT_EXEC_PRE = 2;\r
105                 const PARAM_EVT_EXEC_POST = 3;\r
106                 const PARAM_EVT_FETCH_PRE = 4;\r
107                 const PARAM_EVT_FETCH_POST = 5;\r
108                 const PARAM_EVT_NORMALIZE = 6;\r
109 \r
110                 const MYSQL_ATTR_INIT_COMMAND = 1002;\r
111         }\r
112 \r
113         /**\r
114          * PDOException class of dummy\r
115          */\r
116         class PDOException extends Exception\r
117         {}\r
118 }\r
119 \r
120 /**\r
121  * MysqlPDO class that wraps the mysql_ or mysqli_ function like PDO class\r
122  */\r
123 class MysqlPDO\r
124 {\r
125         // Prefix function name\r
126         public static $handler;\r
127 \r
128         private $dbcon;\r
129 \r
130         /**\r
131          * Creates a PDO instance representing a connection to a MySQL database.\r
132          * @param string $dsn DSN\r
133          * @param string $username UserName\r
134          * @param string $password Password\r
135          * @param mixed $driver_options Options[optional]\r
136          * @throws PDOException Thrown when failed to connect to the database.\r
137          */\r
138         public function __construct($dsn, $username, $password, $driver_options = '')\r
139         {\r
140                 // select use function\r
141                 if ( function_exists('mysql_query') )\r
142                 {\r
143                         MysqlPDO::$handler = 'mysql_';\r
144                 }\r
145                 else if ( function_exists('mysqli_query') )\r
146                 {\r
147                         MysqlPDO::$handler = 'mysqli_';\r
148                 }\r
149                 else\r
150                 {\r
151                         throw new PDOException('Can not be found mysql_ or mysqli_ functions.', 'IM000');\r
152                 }\r
153 \r
154                 if ( preg_match('/host=([^;]+)/', $dsn, $matches) )\r
155                 {\r
156                         $host = $matches[1];\r
157                 }\r
158                 else\r
159                 {\r
160                         throw new PDOException('Host has not been set.', '01000');\r
161                 }\r
162                 if ( preg_match('/port=([^;]+)/', $dsn, $matches) )\r
163                 {\r
164                         $host .= ':' . $matches[1];\r
165                 }\r
166 \r
167                 // mysql connect\r
168                 $this->dbcon = @call_user_func(MysqlPDO::$handler . 'connect', $host, $username, $password);\r
169 \r
170                 if ( $this->dbcon == FALSE )\r
171                 {\r
172                         throw new PDOException('Failed to connect to the server.', '01000');\r
173                 }\r
174 \r
175                 // select database\r
176                 if ( preg_match('/dbname=([^;]+)/', $dsn, $matches) )\r
177                 {\r
178                         $dbname = $matches[1];\r
179                         if ( $dbname )\r
180                         {\r
181                                 if ( MysqlPDO::$handler == 'mysql_' )\r
182                                 {\r
183                                         call_user_func(MysqlPDO::$handler . 'select_db', $dbname, $this->dbcon);\r
184                                 }\r
185                                 else\r
186                                 {\r
187                                         call_user_func(MysqlPDO::$handler . 'select_db', $this->dbcon, $dbname);\r
188                                 }\r
189 \r
190                                 // set use character\r
191                                 $charset = 'utf8';\r
192                                 if ( is_array($driver_options) && array_key_exists(PDO::MYSQL_ATTR_INIT_COMMAND, $driver_options) )\r
193                                 {\r
194                                         if ( preg_match('/SET\s+CHARACTER\s+SET\s+\'?([a-z0-9_-]+)\'?/', $driver_options[PDO::MYSQL_ATTR_INIT_COMMAND], $matches) )\r
195                                         {\r
196                                                 $charset = $matches[1];\r
197                                         }\r
198                                 }\r
199                                 $server_info = call_user_func(MysqlPDO::$handler . 'get_server_info', $this->dbcon);\r
200                                 $mysql_version = preg_replace('/^([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{1,2})(.*)$/', '$1.$2.$3', $server_info);\r
201 \r
202                                 if ( version_compare($mysql_version, '5.0.7', '>=') && function_exists(MysqlPDO::$handler . 'set_charset') )\r
203                                 {\r
204                                         call_user_func(MysqlPDO::$handler . 'set_charset', $charset);\r
205                                 }\r
206                                 else if ( version_compare($mysql_version, '5.0.7', '<') )\r
207                                 {\r
208                                         $this->exec("SET CHARACTER SET '{$charset}';");\r
209                                 }\r
210                                 else\r
211                                 {\r
212                                         $this->exec("SET NAMES '{$charset}';");\r
213                                 }\r
214                         }\r
215                 }\r
216         }\r
217 \r
218         /**\r
219          * Close the connection to the MySQL server.\r
220          */\r
221         public function __destruct()\r
222         {\r
223                 if ( $this->dbcon )\r
224                 {\r
225                         @call_user_func(MysqlPDO::$handler . 'close', $this->dbcon);\r
226                 }\r
227         }\r
228 \r
229         /**\r
230          * Not supported\r
231          */\r
232         public function beginTransaction()\r
233         {\r
234                 return FALSE;\r
235         }\r
236 \r
237         /**\r
238          * Not supported\r
239          */\r
240         public function commit()\r
241         {\r
242                 return FALSE;\r
243         }\r
244 \r
245         /**\r
246          * Fetch the SQLSTATE associated with the last operation.\r
247          * However, if successful '00000' Otherwise, the return to '01000'.\r
248          * @return string Error code\r
249          */\r
250         public function errorCode()\r
251         {\r
252                 $errno = call_user_func(MysqlPDO::$handler . 'errno', $this->dbcon);\r
253                 return $errno === 0 ? '00000' : '01000';\r
254         }\r
255 \r
256         /**\r
257          * To get extended error information associated with the last operation.\r
258          * Element 0: if successful '00000' Otherwise, the return to '01000'\r
259          * Element 1: The return value of mysql_errno()\r
260          * Element 2: The return value of mysql_error()\r
261          * @return array Array of error information\r
262          */\r
263         public function errorInfo()\r
264         {\r
265                 $errno = call_user_func(MysqlPDO::$handler . 'errno', $this->dbcon);\r
266                 $error = call_user_func(MysqlPDO::$handler . 'error', $this->dbcon);\r
267                 return array($errno === 0 ? '00000' : '01000', $errno, $error);\r
268         }\r
269 \r
270         public function exec($statement)\r
271         {\r
272                 @call_user_func(MysqlPDO::$handler . 'query', $statement, $this->dbcon);\r
273                 return @call_user_func(MysqlPDO::$handler . 'affected_rows', $this->dbcon);\r
274         }\r
275 \r
276         public function getAttribute($attribute)\r
277         {\r
278                 switch ( $attribute )\r
279                 {\r
280                         case PDO::ATTR_SERVER_VERSION:\r
281                                 return call_user_func(MysqlPDO::$handler . 'get_server_info', $this->dbcon);\r
282                                 break;\r
283                         case PDO::ATTR_CLIENT_VERSION:\r
284                                 return call_user_func(MysqlPDO::$handler . 'get_client_info');\r
285                                 break;\r
286                         default:\r
287                                 return FALSE;\r
288                 }\r
289         }\r
290 \r
291         public static function getAvailableDrivers()\r
292         {\r
293                 return array('mysql');\r
294         }\r
295 \r
296         /**\r
297          * Not supported\r
298          */\r
299         public function inTransaction()\r
300         {\r
301                 return FALSE;\r
302         }\r
303 \r
304         public function lastInsertId($name = null)\r
305         {\r
306                 return call_user_func(MysqlPDO::$handler . 'insert_id', $this->dbcon);\r
307         }\r
308 \r
309         /**\r
310          * Not supported\r
311          */\r
312         public function prepare($statement, $driver_options = array())\r
313         {\r
314                 return FALSE;\r
315         }\r
316 \r
317         public function query($statement)\r
318         {\r
319                 $result = @call_user_func(MysqlPDO::$handler . 'query', $statement, $this->dbcon);\r
320                 return ($result == FALSE) ? FALSE : new MysqlPDOStatement($statement, $result, $this->dbcon);\r
321         }\r
322 \r
323         public function quote($string, $parameter_type = PDO::PARAM_STR)\r
324         {\r
325                 switch ( $parameter_type )\r
326                 {\r
327                         case PDO::PARAM_NULL:\r
328                                 return 'null';\r
329                         case PDO::PARAM_BOOL:\r
330                                 return $string ? '1' : '0';\r
331                         default:\r
332                                 if ( $parameter_type == PDO::PARAM_INT && is_numeric($string) )\r
333                                 {\r
334                                         return $string;\r
335                                 }\r
336                                 else\r
337                                 {\r
338                                         return '\'' . call_user_func(MysqlPDO::$handler . 'real_escape_string', $string) . '\'';\r
339                                 }\r
340                 }\r
341         }\r
342 \r
343         /**\r
344          * Not supported\r
345          */\r
346         public function rollBack()\r
347         {\r
348                 return FALSE;\r
349         }\r
350 \r
351         /**\r
352          * Not supported\r
353          */\r
354         public function setAttribute($attribute, $value)\r
355         {\r
356                 return FALSE;\r
357         }\r
358 }\r
359 \r
360 /**\r
361  * MysqlPDOStatement class PDOStatement class like.\r
362  */\r
363 class MysqlPDOStatement implements Iterator\r
364 {\r
365         private $result;\r
366         private $dbcon;\r
367         private $_queryString = '';\r
368 \r
369         private $def_col_num = 0;\r
370         private $def_class_name = 'stdClass';\r
371         private $def_ctorargs = null;\r
372         private $bind_object = null;\r
373 \r
374         public function __get($name)\r
375         {\r
376                 if ( $name == 'queryString' )\r
377                 {\r
378                         return $this->_queryString;\r
379                 }\r
380         }\r
381 \r
382         public function __construct($query, $result, $dbconnect = null)\r
383         {\r
384                 $this->dbcon = $dbconnect;\r
385                 $this->_queryString = $query;\r
386                 $this->result = $result;\r
387         }\r
388 \r
389         public function __destruct()\r
390         {\r
391                 $this->result = null;\r
392         }\r
393 \r
394         /**\r
395          * Not supported\r
396          */\r
397         public function bindColumn($column, &$param, $type, $maxlen, $driverdata)\r
398         {\r
399                 return FALSE;\r
400         }\r
401 \r
402         /**\r
403          * Not supported\r
404          */\r
405         public function bindParam($parameter, &$variable, $data_type = PDO::PARAM_STR, $length, $driver_options)\r
406         {\r
407                 return FALSE;\r
408         }\r
409 \r
410         /**\r
411          * Not supported\r
412          */\r
413         public function bindValue($parameter, $value, $data_type = PDO::PARAM_STR)\r
414         {\r
415                 return FALSE;\r
416         }\r
417 \r
418         public function closeCursor()\r
419         {\r
420                 return call_user_func(MysqlPDO::$handler . 'free_result', $this->result);\r
421         }\r
422 \r
423         public function columnCount()\r
424         {\r
425                 return call_user_func(MysqlPDO::$handler . 'num_fields', $this->result);\r
426         }\r
427 \r
428         /**\r
429          * Not supported\r
430          */\r
431         public function debugDumpParams()\r
432         {\r
433                 return;\r
434         }\r
435 \r
436         public function errorCode()\r
437         {\r
438                 $errno = call_user_func(MysqlPDO::$handler . 'errno', $this->dbcon);\r
439                 return $errno === 0 ? '00000' : '01000';\r
440         }\r
441 \r
442         public function errorInfo()\r
443         {\r
444                 $errno = call_user_func(MysqlPDO::$handler . 'errno', $this->dbcon);\r
445                 $error = call_user_func(MysqlPDO::$handler . 'error', $this->dbcon);\r
446                 return array($errno === 0 ? '00000' : '01000', $errno, $error);\r
447         }\r
448 \r
449         /**\r
450          * Not supported\r
451          */\r
452         public function execute($input_parameters)\r
453         {\r
454                 return FALSE;\r
455         }\r
456 \r
457         public function fetch($fetch_style, $cursor_orientation = PDO::FETCH_ORI_NEXT, $cursor_offset = 0)\r
458         {\r
459                 if ( !is_resource($this->result) || $cursor_orientation != PDO::FETCH_ORI_NEXT )\r
460                 {\r
461                         return FALSE;\r
462                 }\r
463 \r
464                 switch ( $fetch_style )\r
465                 {\r
466                         case PDO::FETCH_ASSOC:\r
467                                 return @call_user_func(MysqlPDO::$handler . 'fetch_array', $this->result, MYSQL_ASSOC);\r
468                         case PDO::FETCH_BOTH:\r
469                                 return @call_user_func(MysqlPDO::$handler . 'fetch_array', $this->result, MYSQL_BOTH);\r
470                         case PDO::FETCH_NUM:\r
471                                 return @call_user_func(MysqlPDO::$handler . 'fetch_array', $this->result, MYSQL_NUM);\r
472                         case PDO::FETCH_OBJ:\r
473                                 return $this->fetchObject('stdClass');\r
474                         case PDO::FETCH_CLASS:\r
475                                 return $this->fetchObject();\r
476                         case PDO::FETCH_BOUND:\r
477                                 return FALSE; // Not supported\r
478                         case PDO::FETCH_INTO:\r
479                                 return FALSE; // Not supported\r
480                         case PDO::FETCH_LAZY:\r
481                                 return FALSE; // Not supported\r
482                         default:\r
483                                 return FALSE;\r
484                 }\r
485         }\r
486 \r
487         public function fetchAll($fetch_style, $fetch_argument, $ctor_args = array())\r
488         {\r
489                 if ( ($fetch_style & PDO::FETCH_COLUMN) != 0 )\r
490                 {\r
491                         return FALSE;\r
492                 }\r
493 \r
494                 $ret = array();\r
495                 while ( $row = $this->fetch(PDO::FETCH_BOTH) )\r
496                 {\r
497                         $ret[] = $row;\r
498                 }\r
499                 return $ret;\r
500         }\r
501 \r
502         public function fetchColumn($column_number = null)\r
503         {\r
504                 if ( !isset($column_number) )\r
505                 {\r
506                         $column_number = $this->def_col_num;\r
507                 }\r
508                 $ret = $this->fetch(PDO::FETCH_NUM);\r
509                 return $ret[$column_number];\r
510         }\r
511 \r
512         public function fetchObject($class_name = null, $ctor_args = null)\r
513         {\r
514                 $c_name = isset($class_name) ? $class_name : $this->def_class_name;\r
515                 $c_args = isset($ctor_args) ? $ctor_args : $this->def_ctorargs;\r
516                 if ( $c_args == null )\r
517                 {\r
518                         return @call_user_func(MysqlPDO::$handler . 'fetch_object', $this->result, $c_name);\r
519                 }\r
520                 else\r
521                 {\r
522                         return @call_user_func(MysqlPDO::$handler . 'fetch_object', $this->result, $c_name, $c_args);\r
523                 }\r
524         }\r
525 \r
526         public function getAttribute($attribute)\r
527         {\r
528                 switch ( $attribute )\r
529                 {\r
530                         default:\r
531                                 return FALSE;\r
532                 }\r
533         }\r
534 \r
535         /**\r
536          * Not supported\r
537          */\r
538         public function getColumnMeta($column)\r
539         {\r
540                 $result = array();\r
541                 if ( MysqlPDO::$handler == 'mysql_' )\r
542                 {\r
543                         $result['name'] = @call_user_func(MysqlPDO::$handler . 'field_name', $this->result, $column);\r
544                 }\r
545                 return $result;\r
546         }\r
547 \r
548         /**\r
549          * Not supported\r
550          */\r
551         public function nextRowset()\r
552         {\r
553                 return FALSE;\r
554         }\r
555 \r
556         public function rowCount()\r
557         {\r
558                 if ( @call_user_func(MysqlPDO::$handler . 'affected_rows', $this->result) == FALSE )\r
559                 {\r
560                         return @call_user_func(MysqlPDO::$handler . 'num_rows', $this->result);\r
561                 }\r
562                 else\r
563                 {\r
564                         return @call_user_func(MysqlPDO::$handler . 'affected_rows', $this->result);\r
565                 }\r
566         }\r
567 \r
568         /**\r
569          * Not supported\r
570          */\r
571         public function setAttribute($attribute, $value)\r
572         {\r
573                 return FALSE;\r
574         }\r
575 \r
576         public function setFetchMode($mode, &$mode_argument, $ctorargs)\r
577         {\r
578                 switch ( $mode )\r
579                 {\r
580                         case PDO::FETCH_COLUMN:\r
581                                 $this->def_col_num = $mode_argument;\r
582                                 break;\r
583                         case PDO::FETCH_CLASS:\r
584                                 $this->def_class_name = $mode_argument;\r
585                                 $this->def_ctorargs = $ctorargs;\r
586                                 break;\r
587                         case PDO::FETCH_INTO:\r
588                                 $this->bind_object = &$mode_argument;\r
589                                 return FALSE; // Not supported\r
590                 }\r
591                 return 1;\r
592         }\r
593 \r
594         // Iterator\r
595         private $iterator_value;\r
596 \r
597         function rewind()\r
598         {}\r
599 \r
600         function next()\r
601         {}\r
602 \r
603         function valid()\r
604         {\r
605                 return ($this->iterator_value = $this->fetch(PDO::FETCH_BOTH));\r
606         }\r
607 \r
608         function current()\r
609         {\r
610                 return $this->iterator_value;\r
611         }\r
612 \r
613         function key()\r
614         {\r
615                 return null;\r
616         }\r
617 }\r