OSDN Git Service

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