EDB
[ class tree: EDB ] [ index: EDB ] [ all elements ]

Source for file EDB_MYSQL.php

Documentation is available at EDB_MYSQL.php

  1. <?php
  2. /**
  3.  * Project: EDB_MYSQL :: MySQL abstraction layer
  4.  * File:    EDB/EDB_MYSQL.php
  5.  *
  6.  * The EDB_MYSQL class is mysql abstraction layer that used internally
  7.  * on EDB class.
  8.  *
  9.  * @category    Database
  10.  * @package     EDB
  11.  * @subpackage  EDB_ABSTRACT
  12.  * @author      JoungKyun.Kim <http://oops.org>
  13.  * @copyright   (c) 2018, JoungKyun.Kim
  14.  * @license     BSD License
  15.  * @version     $Id$
  16.  * @link        http://pear.oops.org/package/EDB
  17.  * @filesource
  18.  */
  19.  
  20. /**
  21.  * MySQLi engine for EDB API
  22.  *
  23.  * This class support abstracttion DB layer for MySQLi Engine
  24.  *
  25.  * @package     EDB
  26.  */
  27. Class EDB_MYSQL extends EDB_Common {
  28.     // {{{ properties
  29.     /**#@+
  30.      * @access private
  31.      */
  32.     /**
  33.      * db handler of EDB_MYSQL class
  34.      * @var    object 
  35.      */
  36.     private $db;
  37.     /**
  38.      * The number of query parameter
  39.      * @var    integer 
  40.      */
  41.     private $pno = 0;
  42.     /**#@-*/
  43.     // }}}
  44.  
  45.     // {{{ (object) EDB_MYSQL::__construct ($host, $user, $pass, $db)
  46.     /** 
  47.      * Instantiates an EDB_MYSQL object and opens an mysql database
  48.      *
  49.      * For examples:
  50.      * <code>
  51.      * $db = new EDB_MYSQL ('mysql://localhost', 'user', 'host', 'database');
  52.      * $db = new EDB_MYSQL ('mysql://localhost:3306', 'user', 'host', 'database');
  53.      * $db = new EDB_MYSQL ('mysql://localhost:/var/run/mysqld/mysql.sock', 'user', 'host', 'database');
  54.      * </code>
  55.      *
  56.      * If you add prefix 'p~' before host, you can connect with persistent
  57.      * connection.
  58.      *
  59.      * For Examples:
  60.      * <code>
  61.      * $db = new EDB_MYSQL ('mysql://p~localhost', 'user', 'host', 'database');
  62.      * </code>
  63.      *
  64.      * @access public
  65.      * @return EDB_MYSQL 
  66.      * @param  string  $hostname mysql host
  67.      * @param  string  $user     mysql user
  68.      * @param  string  $password mysql password
  69.      * @param  string  $database mysql database
  70.      */
  71.     function __construct () {
  72.         $_argv = func_get_args ();
  73.         $argv = is_array ($_argv[0]) ? $_argv[0] : $_argv;;
  74.  
  75.         if ( ! extension_loaded ('mysql') )
  76.             throw new myException ('MySQL extension is not loaded on PHP!', E_USER_ERROR);
  77.  
  78.         $o = (object) array (
  79.             'host' => preg_replace ('!^mysql://!', '', $argv[0]),
  80.             'user' => $argv[1],
  81.             'pass' => $argv[2],
  82.             'db'   => $argv[3]
  83.         );
  84.  
  85.         if ( preg_match ('/^([^:]+):(.+)/', $o->host, $matches) ) {
  86.             if ( ! is_numeric ($matches[2]) )
  87.                 $o->host = ':' . $matches[2];
  88.         } else
  89.             $o->host .= ':3306';
  90.  
  91.         if ( preg_match ('/^p~/', $o->host) ) {
  92.             $func = 'mysql_pconnect';
  93.             $o->host = preg_replace ('/^p~/', '', $o->host);
  94.         } else
  95.             $func = 'mysql_connect';
  96.  
  97.         try {
  98.             $this->db = $func ($o->host, $o->user, $o->pass);
  99.             mysql_select_db ($o->db, $this->db);
  100.         } catch ( Exception $e ) {
  101.             throw new myException ($e->getMessage (), $e->getCode(), $e);
  102.         }
  103.     }
  104.     // }}}
  105.  
  106.     // {{{ (string) EDB_MYSQL::get_charset (void)
  107.     /** 
  108.      * Get character set of current database
  109.      *
  110.      * MySQL extension don't support this function
  111.      *
  112.      * @access public
  113.      * @return string Current character set name on DB
  114.      */
  115.     function get_charset () {
  116.         $r = $this->query ('SHOW variables WHERE Variable_name = ?', 's', 'character_set_client');
  117.         if ( $r != 1 )
  118.             return 'Unsupport';
  119.  
  120.         $row = $this->fetch (true);
  121.         return $row->Value;
  122.     }
  123.     // }}}
  124.  
  125.     // {{{ (bool) EDB_MYSQL::set_charset ($charset)
  126.     /** 
  127.      * Set character set of current database
  128.      *
  129.      * @access public
  130.      * @return bool    The name of character set that is supported on database
  131.      * @param  string  name of character set that supported from database
  132.      */
  133.     function set_charset ($char) {
  134.         try {
  135.             $r = false;
  136.  
  137.             if ( is_resource ($this->db) ) {
  138.                 if ( ($r = mysql_set_charset ($char, $this->db)) == false )
  139.                     $this->error = mysql_error ($this->db);
  140.             }
  141.  
  142.             return $r;
  143.         } catch ( Exception $e ) {
  144.             throw new myException ($e->getMessage (), $e->getCode(), $e);
  145.             return false;
  146.         }
  147.     }
  148.     // }}}
  149.  
  150.     // {{{ (string) EDB_MYSQL::escape ($string)
  151.     /** 
  152.      * Escape special characters in a string for use in an SQL statement
  153.      *
  154.      * @access public
  155.      * @return string 
  156.      * @param  string  The string that is to be escaped.
  157.      */
  158.     function escape ($string) {
  159.         return mysql_real_escape_string ($string, $this->db);
  160.     }
  161.     // }}}
  162.  
  163.     // {{{ (int) EDB_MYSQL::query ($query, $param_type, $param1, $param2 ...)
  164.     /** 
  165.      * Performs a query on the database
  166.      *
  167.      * @access public
  168.      * @return integer The number of affected rows or false
  169.      * @param  string  $query The query strings
  170.      * @param  string  $type  (optional) Bind parameter type. See also
  171.      *  {@link http://php.net/manual/en/mysqli-stmt.bind-param.php mysqli_stmt::bind_param}.
  172.      *  <code>
  173.      *  i => integer
  174.      *  d => double
  175.      *  s => string
  176.      *  b => blob
  177.      *  </code>
  178.      * @param  mixed   $param1 (optional) Bind parameter 1
  179.      * @param  mixed   $param2,... (optional) Bind parameter 2 ..
  180.      */
  181.     function query () {
  182.         $_argv = func_get_args ();
  183.         $argv = is_array ($_argv[0]) ? $_argv[0] : $_argv;;
  184.  
  185.         $this->error = null;
  186.  
  187.         $sql = array_shift ($argv);
  188.         $this->pno = count ($argv) ? $this->get_param_number ($sql) : 0;
  189.  
  190.         if ( $this->free )
  191.             $this->free_result ();
  192.  
  193.         // store query in log variable
  194.         $this->queryLog[] = $sql;
  195.  
  196.         /*
  197.          * For no bind query
  198.          */
  199.         if ( $this->pno++ == 0 )
  200.             return $this->no_bind_query ($sql);
  201.  
  202.         /*
  203.          * For bind query
  204.          */
  205.         return $this->bind_query ($sql, $argv);
  206.     }
  207.     // }}}
  208.  
  209.     // {{{ (int) EDB_MYSQL::lastId (void)
  210.     /**
  211.      * 마지막 실행한 쿼리에서 자동으로 생성된 ID(auto increment)값을 반환
  212.      *
  213.      * @since  2.0.4
  214.      * @access public
  215.      * @return integer|false
  216.      */
  217.     function lastId () {
  218.         return mysql_insert_id ($this->db);
  219.     }
  220.     // }}}
  221.  
  222.     // {{{ (boo) EDB_MYSQL::seek ($offset)
  223.     /**
  224.      * Adjusts the result pointer to an arbitrary row in the result
  225.      *
  226.      * @access public
  227.      * @return boolean 
  228.      * @param  integer Must be between zero and the total number of rows minus one
  229.      */
  230.     function seek ($offset) {
  231.         if ( ! is_resource ($this->result) )
  232.             return false;
  233.  
  234.         try {
  235.             return mysql_data_seek ($this->result, $offset);
  236.         } catch ( Exception $e ) {
  237.             throw new myException ($e->getMessage (), $e->getCode(), $e);
  238.             return false;
  239.         }
  240.     }
  241.     // }}}
  242.  
  243.     // {{{ (object) EDB_MYSQL::fetch (void)
  244.     /**
  245.      * Fetch a result row as an associative object
  246.      *
  247.      * @access public
  248.      * @return object The object of fetched a result row or false
  249.      * @param  boolean (optional) fetch 수행 후 result를 free한다.
  250.      *                  (기본값: false) EDB >= 2.0.3
  251.      */
  252.     function fetch ($free = false) {
  253.         if ( ! is_resource ($this->result) )
  254.             return false;
  255.  
  256.         try {
  257.             $r = mysql_fetch_object ($this->result);
  258.             if ( $free )
  259.                 $this->free_result ();
  260.             return $r;
  261.         } catch ( Exception $e ) {
  262.             throw new myException ($e->getMessage (), $e->getCode(), $e);
  263.             return false;
  264.         }
  265.     }
  266.     // }}}
  267.  
  268.     // {{{ (array) EDB_MYSQL::fetch_all ($free = true)
  269.     /**
  270.      * Fetch all result rows as an associative object
  271.      *
  272.      * @access public
  273.      * @return array The fetched result rows
  274.      * @param  boolean (optional) free result set after fetch.
  275.      *                  Defaluts is true.
  276.      */
  277.     function fetch_all ($true = true) {
  278.         $row = array ();
  279.  
  280.         while ( ($r = $this->fetch ()) !== false )
  281.             $row[] = $r;
  282.  
  283.         if ( $true )
  284.             $this->free_result ();
  285.  
  286.         return $row;
  287.     }
  288.     // }}}
  289.  
  290.     // {{{ (bool) EDB_MYSQL::free_result (void)
  291.     /**
  292.      * Frees stored result memory for the given statement handle
  293.      *
  294.      * @access public
  295.      * @return boolean 
  296.      * @param  void 
  297.      */
  298.     function free_result () {
  299.         if ( ! $this->free ) return true;
  300.         $this->free = false;
  301.  
  302.         if ( ! is_resource ($this->result) )
  303.             return true;
  304.  
  305.         try {
  306.             return mysql_free_result ($this->result);
  307.         } catch ( Exception $e ) {
  308.             throw new myException ($e->getMessage (), $e->getCode(), $e);
  309.             return false;
  310.         }
  311.     }
  312.     // }}}
  313.  
  314.     // {{{ (string) EDB_MYSQL::field_name ($index)
  315.     /**
  316.      * Get the name of the specified field in a result
  317.      *
  318.      * @access public
  319.      * @return string|false
  320.      * @param  integer The numerical field offset. The field_offset starts
  321.      *                  at 0. If field_offset does not exist, return false
  322.      *                  and an error of level E_WARNING is also issued.
  323.      * @see http://php.net/manual/en/function.mysql-field-name.php mysql_field_name()
  324.      */
  325.     function field_name ($index) {
  326.         try {
  327.             if ( ! is_resource ($this->result) )
  328.                 return false;
  329.  
  330.             return mysql_field_name ($this->result, $index);
  331.         } catch ( Exception $e ) {
  332.             throw new myException ($e->getMessage (), $e->getCode(), $e);
  333.             return false;
  334.         }
  335.     }
  336.     // }}}
  337.  
  338.     // {{{ (string) EDB_MYSQL::field_type ($index)
  339.     /**
  340.      * Get the type of the specified field in a result
  341.      *
  342.      * @access public
  343.      * @return string|false
  344.      * @param  integer The numerical field offset. The field_offset starts
  345.      *                  at 0. If field_offset does not exist, return false
  346.      *                  and an error of level E_WARNING is also issued.
  347.      * @see http://php.net/manual/en/function.mysql-field-type.php mysql_field_type()
  348.      */
  349.     function field_type ($index) {
  350.         try {
  351.             if ( ! is_resource ($this->result) )
  352.                 return false;
  353.  
  354.             return mysql_field_type ($this->result, $index);
  355.         } catch ( Exception $e ) {
  356.             throw new myException ($e->getMessage (), $e->getCode(), $e);
  357.             return false;
  358.         }
  359.     }
  360.     // }}}
  361.  
  362.     // {{{ (int) EDB_MYSQL::num_fields (void)
  363.     /**
  364.      * Get number of fields in result
  365.      *
  366.      * @access public
  367.      * @return integer|false
  368.      * @see http://php.net/manual/en/function.mysql-num-fields.php mysql_num_fields()
  369.      */
  370.     function num_fields () {
  371.         try {
  372.             if ( ! is_resource ($this->result) )
  373.                 return false;
  374.  
  375.             return mysql_num_fields ($this->result);
  376.         } catch ( Exception $e ) {
  377.             throw new myException ($e->getMessage (), $e->getCode(), $e);
  378.             return false;
  379.         }
  380.     }
  381.     // }}}
  382.  
  383.  
  384.     // {{{ (void) EDB_MYSQL::trstart (void)
  385.     /**
  386.      * DB transaction 을 시작한다.
  387.      *
  388.      * @access public
  389.      * @return void 
  390.      */
  391.     function trstart () {
  392.         $this->db->query ('BEGIN');
  393.     }
  394.     // }}}
  395.  
  396.     // {{{ (void) EDB_MYSQL::trend ($v)
  397.     /**
  398.      * DB transaction 을 종료한다.
  399.      *
  400.      * @access public
  401.      * @return void 
  402.      * @param bool false일경우 rollback을 수행한다.
  403.      */
  404.     function trend ($v = true) {
  405.         $sql = ($v === false) ? 'ROLLBACK' : 'COMMIT';
  406.         $this->db->query ($sql);
  407.     }
  408.     // }}}
  409.  
  410.  
  411.  
  412.     // {{{ (void) EDB_MYSQL::close (void)
  413.     /**
  414.      * Close the db handle
  415.      *
  416.      * @access public
  417.      * @return void 
  418.      * @param  void 
  419.      */
  420.     function close () {
  421.         if ( is_resource ($this->db) ) {
  422.             mysql_close ($this->db);
  423.             unset ($this->db);
  424.         }
  425.     }
  426.     // }}}
  427.  
  428.     /*
  429.      * Priavte functions
  430.      */
  431.     // {{{ private (int) EDB_MYSQL::no_bind_query ($sql)
  432.     /** 
  433.      * Performs a query on the database
  434.      *
  435.      * @access private
  436.      * @return integer The number of affected rows or false
  437.      * @param  string  The query strings
  438.      */
  439.     private function no_bind_query ($sql) {
  440.         try {
  441.             $this->result = mysql_query ($sql, $this->db);
  442.             if ( mysql_errno ($this->db) ) {
  443.                 $this->free = false;
  444.                 throw new myException (mysql_error ($this->db), E_USER_WARNING);
  445.                 return false;
  446.             }
  447.         } catch ( Exception $e ) {
  448.             $this->free = false;
  449.             throw new myException ($e->getMessage (), $e->getCode(), $e);
  450.             return false;
  451.         }
  452.  
  453.         $this->switch_freemark ();
  454.  
  455.         if ( preg_match ('/^(update|insert|delete|replace)/i', trim ($sql)) ) {
  456.             /* Insert or update, or delete query */
  457.             return mysql_affected_rows ($this->db);
  458.         } else if ( preg_match ('/create|drop/i', trim ($sql)) ) {
  459.             return 1;
  460.         }
  461.  
  462.         return mysql_num_rows ($this->result);
  463.     }
  464.     // }}}
  465.  
  466.     // {{{ private (int) EDB_MYSQL::bind_query ($sql, $parameters)
  467.     /** 
  468.      * Performs a bind query on the database
  469.      *
  470.      * @access private
  471.      * @return integer The number of affected rows or false
  472.      * @param  string  The query strings
  473.      * @param  array   (optional) Bind parameter type
  474.      */
  475.     private function bind_query ($sql, $params) {
  476.         if ( $this->pno != count ($params) || $this->check_param ($params) === false ) {
  477.             throw new myException (
  478.                 'Number of elements in query doesn\'t match number of bind variables',
  479.                 E_USER_WARNING
  480.             );
  481.             return false;
  482.         }
  483.  
  484.         $parano = strlen ($params[0]);
  485.         for ( $i=0, $j=1; $i<$parano; $i++, $j++ ) {
  486.             switch ($params[0][$i]) {
  487.                 case 'c' :
  488.                 case 'b' :
  489.                     if ( is_object ($params[$j]) )
  490.                         $params[$j] = $this->escape ($params[$j]->data);
  491.                     $params[$j] = $this->escape ($params[$j]);
  492.                     break;
  493.             }
  494.         }
  495.  
  496.         $query = $this->bind_param ($sql, $params);
  497.         return $this->no_bind_query ($query);
  498.     }
  499.     // }}}
  500.  
  501.     function __destruct () {
  502.         try {
  503.             $this->free_result ();
  504.             $this->close ();
  505.         } catch ( Exception $e ) { }
  506.     }
  507. }
  508.  
  509. /*
  510.  * Local variables:
  511.  * tab-width: 4
  512.  * c-basic-offset: 4
  513.  * End:
  514.  * vim: set filetype=php noet sw=4 ts=4 fdm=marker:
  515.  * vim600: noet sw=4 ts=4 fdm=marker
  516.  * vim<600: noet sw=4 ts=4
  517.  */
  518. ?>

Documentation generated on Fri, 30 Aug 2024 06:10:14 +0900 by phpDocumentor 1.4.4