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

Source for file mysql.php

Documentation is available at mysql.php

  1. <?php
  2. /**
  3.  * sThread MYSQL module
  4.  * 
  5.  * @category    Network
  6.  * @package     sThread
  7.  * @subpackage  sThread_Module
  8.  * @author      JoungKyun.Kim <http://oops.org>
  9.  * @copyright   (c) 2015 OOPS.ORG
  10.  * @license     BSD License
  11.  * @version     $Id$
  12.  * @link        http://pear.oops.org/package/sThread
  13.  * @see         http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol MySQL Internals ClientServer Protocol
  14.  * @filesource
  15.  */
  16.  
  17. /**
  18.  * MYSQL module Class
  19.  * 
  20.  * MYSQL 모듈에 사용할 수 있는 모듈 option은 다음과 같다.
  21.  *
  22.  * <ul>
  23.  *     <li><b>user:</b>     로그인 유저</li>
  24.  *     <li><b>pass:</b>     로그인 암호</li>
  25.  *     <li><b>database:</b> 질의할 데이터베이스 이름</li>
  26.  *     <li><b>query:</b>    쿼리 문자열</li>
  27.  *     <li><b>charset:</b>  클라이언트 문자셋</li>
  28.  * </ul>
  29.  *
  30.  * 예제:
  31.  * <code>
  32.  *   sThread::execute ('domain.com:3306:mysql|query=>select count(*) FROM test', 2, 'tcp');
  33.  * </code>
  34.  *
  35.  * @category    Network
  36.  * @package     sThread
  37.  * @subpackage  sThread_Module
  38.  * @author      JoungKyun.Kim <http://oops.org>
  39.  * @copyright   (c) 2015 OOPS.ORG
  40.  * @license     BSD License
  41.  * @link        http://pear.oops.org/package/sThread
  42.  * @see         http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol MySQL Internals ClientServer Protocol
  43.  */
  44. Class sThread_MYSQL {
  45.     // {{{ Base properteis
  46.     /**#@+
  47.      * @access public
  48.      */
  49.     /**
  50.      * 이 변수의 값이 true로 셋팅이 되면, clear_session
  51.      * method를 만들어 줘야 한다. 반대로 false 상태에서는
  52.      * clear_session method가 존재하지 않아도 상관이 없다.
  53.      *
  54.      * @var bool 
  55.      */
  56.     static public $clearsession = true;
  57.     /**
  58.      * MYSQL 모듈이 사용하는 protocol
  59.      * @var string 
  60.      */
  61.     static public $protocol = 'tcp';
  62.     /**
  63.      * MYSQL 모듈이 사용하는 기본 포트 번호
  64.      * @var int 
  65.      */
  66.     static public $port = 3306;
  67.  
  68.     const MYSQL_BANNER    1;
  69.     const MYSQL_SENDAUTH  2;
  70.     const MYSQL_HANDSHAKE 3;
  71.     const MYSQL_SENDQUERY 4;
  72.     const MYSQL_QUERYRES  5;
  73.     /**
  74.      * 에러가 발생했을 경우, MYSQL_QUIT 메소드가 정의가 되어있으면,
  75.      * parent::socketColose에 의해서 자동으로 MYSQL_QUIT이 호출이
  76.      * 된다.
  77.      */
  78.     const MYSQL_QUIT      6;
  79.     const MYSQL_CLOSE     7;
  80.     /**#@-*/
  81.     // }}}
  82.  
  83.     // {{{ Per module properteis
  84.     /**#@+
  85.      * @access private
  86.      */
  87.     const MYSQL_COM_QUIT    0x01;
  88.     const MYSQL_COM_INIT_DB 0x02;
  89.     const MYSQL_COM_QUERY   0x03;
  90.  
  91.     const MYSQL_RET_ERROR 0x00;
  92.     const MYSQL_RET_OK    0x01;
  93.     const MYSQL_RET_QUERY 0x02;
  94.     const MYSQL_RET_EOF   0x03;
  95.  
  96.     /* user define variable */
  97.     static private $server;
  98.     static private $qstatus;
  99.     static private $columnno;
  100.     static private $columnid;
  101.     static private $rowid;
  102.     static private $column;
  103.     static private $r;
  104.     /**#@-*/
  105.     // }}}
  106.  
  107.     // {{{ (void) sThread_MYSQL::__construct (void)
  108.     /**
  109.      * Class OOP 형식 초기화 메소드
  110.      * @access public
  111.      * @return sThread_MYSQL 
  112.      */
  113.     function __construct ({
  114.         self::init ();
  115.         $this->clearsession = &self::$clearsession;
  116.         $this->port         = &self::$port;
  117.         $this->protocol     = &self::$protocol;
  118.     }
  119.     // }}}
  120.  
  121.     // {{{ (void) sThread_MYSQL::init (void)
  122.     /**
  123.      * mysql 모듈을 초기화 한다.
  124.      *
  125.      * @access public
  126.      * @return void 
  127.      */
  128.     function init ({
  129.         self::$clearsession true;
  130.         self::$port         3306;
  131.         self::$protocol     'tcp';
  132.  
  133.         self::$server       array ();
  134.         self::$qstatus      array ();
  135.         self::$columnno     array ();
  136.         self::$columnid     array ();
  137.         self::$rowid        array ();
  138.         self::$column       array ();
  139.         self::$r            array ();
  140.     }
  141.     // }}}
  142.  
  143.     // {{{ (int) sThread_MYSQL::check_buf_status ($status)
  144.     /**
  145.      * 현재 상태가 event read 상태인지 event write 상태인지
  146.      * 를 판단한다.
  147.      *
  148.      * @access public
  149.      * @return int 
  150.      * @param  int    현재 status
  151.      */
  152.     function check_buf_status ($status{
  153.         switch ($status{
  154.         case :
  155.         case self::MYSQL_BANNER :
  156.             return Vari::EVENT_READY_RECV;
  157.             break;
  158.         case self::MYSQL_SENDAUTH:
  159.             return Vari::EVENT_READY_SEND;
  160.             break;
  161.         case self::MYSQL_HANDSHAKE:
  162.             return Vari::EVENT_READY_RECV;
  163.             break;
  164.         case self::MYSQL_SENDQUERY:
  165.             return Vari::EVENT_READY_SEND;
  166.             break;
  167.         case self::MYSQL_QUERYRES:
  168.             return Vari::EVENT_READY_RECV;
  169.             break;
  170.         case self::MYSQL_QUIT:
  171.             return Vari::EVENT_READY_SEND;
  172.             break;
  173.         case self::MYSQL_CLOSE :
  174.             return Vari::EVENT_READY_CLOSE;
  175.             break;
  176.         default :
  177.             return Vari::EVENT_UNKNOWN;
  178.         }
  179.     }
  180.     // }}}
  181.  
  182.     // {{{ (string) sThread_MYSQL::call_status ($status, $call = false)
  183.     /**
  184.      * 현재의 status(integer) 또는 현재 status의 handler 이름을
  185.      * 반환한다.
  186.      *
  187.      * @access public
  188.      * @return int|string
  189.      * @param  int        현재 status
  190.      * @param  boolean    true로 설정했을 경우 현재 status의 handler
  191.      *                     이름을 반환한다.
  192.      */
  193.     function call_status ($status$call false{
  194.         switch ($status{
  195.         case self::MYSQL_BANNER :
  196.             $r 'MYSQL_BANNER';
  197.             break;
  198.         case self::MYSQL_SENDAUTH:
  199.             $r 'MYSQL_SENDAUTH';
  200.             break;
  201.         case self::MYSQL_HANDSHAKE:
  202.             $r 'MYSQL_HANDSHAKE';
  203.             break;
  204.         case self::MYSQL_SENDQUERY:
  205.             $r 'MYSQL_SENDQUERY';
  206.             break;
  207.         case self::MYSQL_QUERYRES:
  208.             $r 'MYSQL_QUERYRES';
  209.             break;
  210.         case self::MYSQL_QUIT:
  211.             $r 'MYSQL_QUIT';
  212.             break;
  213.         default:
  214.             $r Vari::EVENT_UNKNOWN;
  215.         }
  216.  
  217.         if $call !== false && $r !== Vari::EVENT_UNKNOWN )
  218.             $r strtolower ($r);
  219.  
  220.         return $r;
  221.     }
  222.     // }}}
  223.  
  224.     // {{{ (boolean) sThread_MYSQL::change_status (&$sess, $key)
  225.     /**
  226.      * 세션의 상태를 단계로 변경한다.
  227.      *
  228.      * @access public
  229.      * @param  boolean  변경한 상태가 마지막 단계일 경우 false를
  230.      *                   반환한다.
  231.      * @param  stdClass sThread 세션 변수 reference
  232.      * @param  int      세션 키
  233.      */
  234.     function change_status (&$sess$key{
  235.         ++$sess->status[$key];
  236.  
  237.         if $sess->status[$key=== self::MYSQL_CLOSE )
  238.             return false;
  239.  
  240.         return true;
  241.     }
  242.     // }}}
  243.  
  244.     // {{{ (void) sThread_MYSQL::set_last_status (&$sess, $key)
  245.     /**
  246.      * 세션의 상태를 마지막 단계로 변경한다.
  247.      *
  248.      * @access public
  249.      * @param  stdClass sThread 세션 변수 reference
  250.      * @param  int      세션 키
  251.      */
  252.     function set_last_status (&$sess$key{
  253.         $sess->status[$keyself::MYSQL_CLOSE;
  254.     }
  255.     // }}}
  256.  
  257.     // {{{ (boolean) sThread_MYSQL::clear_session ($key) {
  258.     /**
  259.      * session에서 사용한 변수(self::$sess)의 값을 정리한다.
  260.      *
  261.      * self::$clearsession == false 일 경우, clear_session method
  262.      * 는 존재하지 않아도 된다.
  263.      *
  264.      * @access public
  265.      * @return void 
  266.      * @param  int    세션 키
  267.      */
  268.     function clear_session ($key{
  269.         Vari::objectUnset (self::$server);
  270.         Vari::objectUnset (self::$qstatus);
  271.         Vari::objectUnset (self::$columnno);
  272.         Vari::objectUnset (self::$columnid);
  273.         Vari::objectUnset (self::$rowid);
  274.         Vari::objectUnset (self::$column);
  275.         Vari::objectUnset (self::$r);
  276.         return;
  277.     }
  278.     // }}}
  279.  
  280.     /*
  281.      * Handler 정의
  282.      *
  283.      * Handler는 call_status 메소드에 정의된 값들 중
  284.      * Vari::EVENT_UNKNOWN를 제외한 모든 status의 constant string을
  285.      * 소문자로해서 만들어야 한다.
  286.      *
  287.      * Handler 이름은 sThread_MODULE::call_status 메소드를
  288.      * 통해서 구할 수 있다.
  289.      *
  290.      * handler는 다음의 구조를 가지며, 실제로 전송을 하거나 받는
  291.      * 것은 libevent가 한다.
  292.      *
  293.      * write handler:
  294.      *       handler_name (&$ses, $key)
  295.      *
  296.      *       write handler는 실제로 전송을 하지 않고 전송할
  297.      *       데이터를 생성해서 반환만 한다.
  298.      *
  299.      * read handler:
  300.      *       handler_name (&$sess, $key, $recv) 
  301.      *
  302.      *       read handler의 반환값은 다음과 같이 지정을 해야 한다.
  303.      *
  304.      *       true  => 모든 전송이 완료
  305.      *       false => 전송 받을 것이 남아 있음
  306.      *       null  => 전송 중 에러 발생
  307.      *
  308.      *       이 의미는 sThread가 read handler에서 결과값에 따라
  309.      *       true는 다음 단계로 전환을 하고, false는 현 status를
  310.      *       유지하며, null의 경우 connection을 종료를 한다.
  311.      */
  312.  
  313.     // {{{ (bool) function mysql_banner (&$sess, $key, $recv)
  314.     /**
  315.      * MySQL banner 확인
  316.      *
  317.      * @access public
  318.      * @return bool|null
  319.      * @param  stdClass 세션 object
  320.      * @param  int      세션 키
  321.      * @param  mixed    read callback에서 전송받은 누적 데이터
  322.      */
  323.     function mysql_banner (&$sess$key$recv{
  324.         if $recv )
  325.             return false;
  326.  
  327.         list ($host$port$type$sess->addr[$key];
  328.  
  329.         $sess->recv[$key.= $recv;
  330.         if strlen ($sess->recv[$key])
  331.             return false;
  332.  
  333.         $server->length self::packet_length ($sess->recv[$key]4;
  334.         $server->packet_number ord ($sess->recv[$key][3]);
  335.  
  336.         if $server->packet_number !== {
  337.             Vari::$res->status[$keyarray (
  338.                 "{$host}:{$port}",
  339.                 false,
  340.                 "Protocol error: Invalid Banner Packet Number : {$server->packet_number}"
  341.             );
  342.             Vari::binaryDecode ($sess->recv[$key]true);
  343.             return null;
  344.         }
  345.  
  346.         if strlen ($sess->recv[$key]!= $server->length )
  347.             return false;
  348.  
  349.         $sess->recv[$keysubstr ($sess->recv[$key]4);
  350.         self::parse_handshake ($sess->recv[$key]self::$server[$key]);
  351.         return true;
  352.     // }}}
  353.  
  354.     // {{{ (binary) function mysql_sendauth (&$sess, $key)
  355.     /**
  356.      * 전송할 인증 데이터 반환
  357.      *
  358.      * @access public
  359.      * @return void 
  360.      * @param  stdClass 세션 object
  361.      * @param  int      세션 키
  362.      */
  363.     function mysql_sendauth (&$sess$key{
  364.         list ($host$port$type$sess->addr[$key];
  365.         $opt $sess->opt[$key];
  366.  
  367.         self::$server[$key]->user     $opt->user;
  368.         self::$server[$key]->passwd   $opt->pass;
  369.         self::$server[$key]->database $opt->database;
  370.         self::$server[$key]->query    $opt->query;
  371.         if isset ($opt->charset) )
  372.             self::$server[$key]->charset  $opt->charset;
  373.  
  374.         return self::send_authenication (self::$server[$key]);
  375.     // }}}
  376.  
  377.     // {{{ (bool) function mysql_handshake (&$sess, $key, $recv)
  378.     /**
  379.      * MySQL 인증 결과 확인 및 handshake 확인
  380.      *
  381.      * @access public
  382.      * @return bool|null
  383.      * @param  stdClass 세션 object
  384.      * @param  int      세션 키
  385.      * @param  mixed  read callback에서 전송받은 누적 데이터
  386.      */
  387.     function mysql_handshake (&$sess$key$recv{
  388.         if $recv )
  389.             return false;
  390.  
  391.         list ($host$port$type$sess->addr[$key];
  392.  
  393.         $sess->recv[$key.= $recv;
  394.         if strlen ($sess->recv[$key])
  395.             return false;
  396.  
  397.         $length self::packet_length ($sess->recv[$key]4;
  398.         $packet_number ord ($sess->recv[$key][3]);
  399.  
  400.         if $packet_number !== {
  401.             Vari::$res->status[$keyarray (
  402.                 "{$host}:{$port}",
  403.                 false,
  404.                 "Protocol error: Invalid Handshake Packet Number : {$packet_number}"
  405.             );
  406.             Vari::binaryDecode ($sess->recv[$key]true);
  407.             return null;
  408.         }
  409.  
  410.         if strlen ($sess->recv[$key]!= $length )
  411.             return false;
  412.  
  413.         $sess->recv[$keysubstr ($sess->recv[$key]4);
  414.         if self::parse_result ($r$sess->recv[$key]!= self::MYSQL_RET_OK {
  415.             Vari::$res->status[$keyarray (
  416.                 "{$host}:{$port}",
  417.                 false,
  418.                 "Protocol error: Authenication Error: {$r->errno} : {$r->message}"
  419.             );
  420.             fwrite ($sess->sock[$key]self::quit_packet ()5);
  421.             Vari::binaryDecode ($sess->recv[$key]true);
  422.             return null;
  423.         }
  424.  
  425.         return true;
  426.     }
  427.     // }}}
  428.  
  429.     // {{{ (binary) function mysql_sendquery (&$sess, $key)
  430.     /**
  431.      * 전송할 쿼리 데이터 반환
  432.      *
  433.      * @access public
  434.      * @return void 
  435.      * @param  stdClass 세션 object
  436.      * @param  int      세션 키
  437.      */
  438.     function mysql_sendquery (&$sess$key{
  439.         return self::query_packet (self::MYSQL_COM_QUERYself::$server[$key]->query);
  440.     // }}}
  441.  
  442.     // {{{ (bool) function mysql_queryres (&$sess, $key, $recv)
  443.     /**
  444.      * MySQL Query 전송 결과 확인
  445.      *
  446.      * @access public
  447.      * @return bool|null
  448.      * @param  stdClass 세션 object
  449.      * @param  int      세션 키
  450.      * @param  mixed    read callback에서 전송받은 누적 데이터
  451.      */
  452.     function mysql_queryres (&$sess$key$recv{
  453.         if $recv )
  454.             return false;
  455.  
  456.         $sess->recv[$key.= $recv;
  457.         if strlen ($sess->recv[$key])
  458.             return false;
  459.  
  460.         list ($host$port$type$sess->addr[$key];
  461.  
  462.         self::init_variable (self::$qstatus[$key]);
  463.         self::init_variable (self::$columnno[$key]);
  464.         self::init_variable (self::$columnid[$key]);
  465.  
  466.         while true {
  467.             $length self::packet_length ($sess->recv[$key]);
  468.             $packet_number ord ($sess->recv[$key][3]);
  469.  
  470.             if $packet_number !== (self::$qstatus[$key1) ) {
  471.                 Vari::$res->status[$keyarray (
  472.                     "{$host}:{$port}",
  473.                     false,
  474.                     "Protocol error: Invalid Query Result Packet Number : {$packet_number}"
  475.                 );
  476.                 Vari::binaryDecode ($sess->recv[$key]true);
  477.                 return null;
  478.             }
  479.  
  480.             $buf substr ($sess->recv[$key]4$length);
  481.             if strlen ($buf!= $length )
  482.                 return false;
  483.  
  484.             // Result Set Header Packet
  485.             if self::$qstatus[$key== {
  486.                 if self::parse_result ($r$buf!= self::MYSQL_RET_QUERY {
  487.                     Vari::$res->status[$keyarray (
  488.                         "{$host}:{$port}",
  489.                         false,
  490.                         "Protocol error: : Invalid Query Result Type"
  491.                     );
  492.                     fwrite ($sess->sock[$key]self::quit_packet ()5);
  493.                     Vari::binaryDecode ($sess->recv[$key]true);
  494.                     return null;
  495.                 }
  496.                 self::$columnno[$keyself::length_coded_binary ($buf);
  497.                 self::$qstatus[$key]++;
  498.  
  499.                 $sess->recv[$keysubstr ($sess->recv[$key]$length 4);
  500.                 continue;
  501.             }
  502.  
  503.             // Column Descriptors
  504.             if self::$qstatus[$key&& self::$qstatus[$keyself::$columnno[$key{
  505.                 self::$column[self::$columnid[$key]]->catalog self::length_coded_string ($buf);
  506.                 self::$column[self::$columnid[$key]]->db self::length_coded_string ($buf);
  507.                 self::$column[self::$columnid[$key]]->table self::length_coded_string ($buf);
  508.                 self::$column[self::$columnid[$key]]->org_table self::length_coded_string ($buf);
  509.                 self::$column[self::$columnid[$key]]->name self::length_coded_string ($buf);
  510.                 self::$column[self::$columnid[$key]]->old_name self::length_coded_string ($buf);
  511.                 self::$column[self::$columnid[$key]]->filler ord ($buf[0]);
  512.                 self::$column[self::$columnid[$key]]->charsetnr unpack ('S'substr ($buf12));
  513.                 self::$column[self::$columnid[$key]]->length unpack ('L'substr ($buf34));
  514.                 self::$column[self::$columnid[$key]]->type '0x' dechex (ord ($buf[7]));
  515.                 self::$column[self::$columnid[$key]]->flag substr ($buf82);
  516.                 self::$column[self::$columnid[$key]]->decimals $buf[10];
  517.                 self::$column[self::$columnid[$key]]->filler unpack ('S'substr ($buf112));
  518.                 $buf substr ($buf13);
  519.                 self::$column[self::$columnid[$key]++]->default self::length_coded_binary ($buf);
  520.  
  521.                 self::$qstatus[$key]++;
  522.  
  523.                 $sess->recv[$keysubstr ($sess->recv[$key]$length 4);
  524.                 continue;
  525.             }
  526.  
  527.             // EOF Packet: end of Field Packets
  528.             if self::$qstatus[$key== (self::$columnno[$key1) ) {
  529.                 if self::parse_result ($r$buf!= self::MYSQL_RET_EOF {
  530.                     Vari::$res->status[$keyarray (
  531.                         "{$host}:{$port}",
  532.                         false,
  533.                         "Protocol error: : Invalid EOF Type of Packet"
  534.                     );
  535.                     fwrite ($sess->sock[$key]self::quit_packet ()5);
  536.                     Vari::binaryDecode ($sess->recv[$key]true);
  537.                     return null;
  538.                 }
  539.  
  540.                 self::$qstatus[$key]++;
  541.                 $sess->recv[$keysubstr ($sess->recv[$key]$length 4);
  542.                 continue;
  543.             }
  544.  
  545.             // Row Data Packets: row contents
  546.             if self::$qstatus[$key(self::$columnno[$key1) ) {
  547.                 //
  548.                 // end of packet
  549.                 // ----------------------------------------------------------------
  550.                 if self::parse_result ($r$buf== self::MYSQL_RET_EOF {
  551.                     //print_r (self::$r);
  552.                     unset ($sess->recv[$key]);
  553.                     if Vari::$result === true )
  554.                         Vari::objectCopy ($sess->data[$key]self::$r);
  555.                     return true;
  556.                 }
  557.                 // ----------------------------------------------------------------
  558.                 //
  559.  
  560.                 self::init_variable (self::$rowid[$key]);
  561.  
  562.                 for $i=0$i<self::$columnno[$key]$i++ {
  563.                     $colname self::$column[$i]->name->data;
  564.                     self::$r[self::$rowid[$key]]->$colname self::length_coded_string ($buf)->data;
  565.                 }
  566.                 self::$rowid[$key]++;
  567.                 self::$qstatus[$key]++;
  568.                 $sess->recv[$keysubstr ($sess->recv[$key]$length 4);
  569.             }
  570.         }
  571.  
  572.         return false;
  573.     // }}}
  574.  
  575.     // {{{ (binary) function mysql_quit (&$sess, $key) {
  576.     /**
  577.      * 전송할 종료 데이터 반환
  578.      *
  579.      * @access public
  580.      * @return void 
  581.      * @param  stdClass 세션 object
  582.      * @param  int      세션 키
  583.      */
  584.     function mysql_quit (&$sess$key{
  585.         return self::quit_packet ();
  586.     // }}}
  587.  
  588.     /*
  589.      * ********************************************************************************
  590.      * User define functions
  591.      * ********************************************************************************
  592.      */
  593.     // {{{ private (void) sThread_MYSQL::init_variabe (&$v)
  594.     private function init_variable (&$v{
  595.         if $v && is_numeric ($v) )
  596.             $v 0;
  597.     }
  598.     // }}}
  599.  
  600.     // {{{ private (void) sThread_MYSQL::hexview ($buf, $len, $t = false)
  601.     private function hexview ($buf$len$t false{
  602.         for $i=0$i<$len$i++ )
  603.             printf ("%3d -> 0x%2x\n"$i+1($t === falseord($buf[$i]$buf[$i]);
  604.     // }}}
  605.  
  606.     // {{{ private (void) sThread_MYSQL::hexview_dump ($buf, $len, $t = false)
  607.     private function hexview_dump ($buf$len$t false{
  608.         for $i=0$i<$len$i++ {
  609.             if $i >= && ($i 8== {
  610.                 echo "  ";
  611.                 if ( ($i 16== )
  612.                     echo "\n";
  613.             }
  614.             printf ("%02x "($t === falseord($buf[$i]$buf[$i]);
  615.         }
  616.         echo "\n";
  617.     // }}}
  618.  
  619.     // {{{ private (void) sThread_MYSQL::scramble (&$to, $salt, $passwd)
  620.     private function scramble (&$to$salt$passwd{
  621.         $pass1 sha1 ($passwdtrue);
  622.         $pass2 sha1 ($pass1true);
  623.         $pass3 sha1 ($salt $pass2true);
  624.         $to $pass3 $pass1;
  625.     // }}}
  626.  
  627.     // {{{ private (integer) sThread_MYSQL::packet_length (&$buf)
  628.     private function packet_length (&$buf{
  629.         $r unpack ('l'substr ($buf03"\0");
  630.         return $r[1];
  631.     // }}}
  632.  
  633.     // {{{ private (object) sThread_MYSQL::length_coded_string (&$buf)
  634.     private function length_coded_string (&$buf{
  635.         $r->length ord ($buf[0]);
  636.         $r->data substr ($buf1$r->length);
  637.  
  638.         $buf substr ($buf$r->length 1);
  639.  
  640.         return $r;
  641.     // }}}
  642.  
  643.     // {{{ private (binary) sThread_MYSQL::length_coded_binary (&$buf)
  644.     private function length_coded_binary (&$buf{
  645.         $v ord ($buf[0]);
  646.         $next 1;
  647.  
  648.         switch ($v{
  649.         case 254 // unsigned 64bit
  650.             $low unpack ('V'substr ($buf14));
  651.             $high unpack ('V'substr ($buf54));
  652.             $v $high[1<< 32;
  653.             $v |= $low[1];
  654.             $next += 8;
  655.             break;
  656.         case 253 // unsigned 24bit
  657.             $tmp unpack ('L'substr ($buf13"\0");
  658.             $v $tmp[1];
  659.             $next += 3;
  660.             break;
  661.         case 252 // unsigned 16bit
  662.             $tmp unpack ('S'substr ($buf12) );
  663.             $v $tmp[1];
  664.             $next += 2;
  665.             break;
  666.         case 251 // NULL of database
  667.             break;
  668.             $v 'NULL';
  669.         default :
  670.             // self
  671.         }
  672.         $buf substr ($buf$next);
  673.         return $v;
  674.     // }}}
  675.  
  676.     /*
  677.      * Parsings
  678.      */
  679.  
  680.     // {{{ private (void) sThread_MYSQL::parse_handshake ($buffer, &$server)
  681.     private function parse_handshake ($buffer&$server{
  682.         $server->protocol_version ord ($buffer[0]);
  683.  
  684.         $server_version_length $handshake_length 44;
  685.         // for mysql 5.5
  686.         if preg_match ('/mysql_native_password/'$buffer) )
  687.             $server_version_length -= 22;
  688.         $server->server_version substr ($buffer1$server_version_length 1);
  689.         $buffer substr ($buffer$server_version_length);
  690.         $buf unpack ('L'$buffer);
  691.         $server->thread_number ord ($buf[1]);
  692.         $server->scramble_buff substr ($buffer48);
  693.  
  694.         $buffer substr ($buffer13);
  695.         $buf unpack ('Scapa/clang/Sstatus'$buffer);
  696.         $server->server_capabilities $buf['capa'];
  697.         $server->charset ord($buf['lang']);
  698.         $server->server_status $buf['status'];
  699.  
  700.         $buffer =  substr ($buffer1812);
  701.         $server->scramble_buff .= $buffer;
  702.     // }}}
  703.  
  704.     // {{{ private (binary) sThread_MYSQL::send_authenication (&$client)
  705.     private function send_authenication (&$client{
  706.         if $client->user )
  707.             return false;
  708.  
  709.         # client_flag
  710.         $s pack ('c*'0x8d0xa60x030x00);
  711.         # max_packaet_size
  712.         $s .= pack('c*'0x000x000x000x01);
  713.         # charset_number (use latin1 -> 51, euckr -> 19 or 0x13, utf8 -> 33)
  714.         $s .= pack ('c'$client->charset);
  715.         # padding
  716.         $s .= pack ('x23');
  717.         # user
  718.         $s .= $client->user pack ('x');
  719.         # password
  720.         self::scramble ($pass$client->scramble_buff$client->passwd);
  721.         # length of $pass is always 20 byte
  722.         $s .= pack ('c'0x14$pass;
  723.         $s .= $client->database pack ('x1');
  724.         $send pack ('Sxc'strlen ($s)++$client->packet_number$s;
  725.  
  726.         return $send;
  727.     // }}}
  728.  
  729.     // {{{ private (integer) sThread_MYSQL::parse_result (&$r, $buf)
  730.     private function parse_result (&$r$buf{
  731.         /*
  732.          * OK Packet           0x00
  733.          * Error Packet        0xff
  734.          * Result Set Packet   1-250 (first byte of Length-Coded Binary)
  735.          * Field Packet        1-250 (first byte of Length-Coded Binary)
  736.          * Row Data Set Packet 1-250 (first byte of Length-Coded Binary)
  737.          * EOF Packet          0xfe
  738.          */
  739.         $r->field_count ord ($buf[0]);
  740.  
  741.         switch ($r->field_count{
  742.             case :
  743.                 // 0x00 OK packet
  744.                 $buf substr ($buf1);
  745.  
  746.                 # affected rows
  747.                 $r->affected_rows self::length_coded_binary ($buf);
  748.                 # insert id
  749.                 $r->insert_id self::length_coded_binary ($buf);
  750.                 # server status
  751.                 $tmp unpack ('S'substr ($buf02));
  752.                 $r->server_status $tmp[1];
  753.                 $tmp unpack ('S'substr ($buf22));
  754.                 $r->warning_count $tmp[1];
  755.                 $buf substr ($buf4);
  756.                 $r->msg self::length_coded_string ($buf);
  757.  
  758.                 return self::MYSQL_RET_OK;
  759.                 break;
  760.             case 254 :
  761.                 // Oxfe EOF packet
  762.                 $buf substr ($buf1);
  763.  
  764.                 $tmp unpack ('S'substr ($buf02));
  765.                 $r->warning_count $tmp[1];
  766.                 $tmp unpack ('S'substr ($buf22));
  767.                 $r->server_status $tmp[1];
  768.  
  769.                 return self::MYSQL_RET_EOF;
  770.                 break;
  771.             case 255 :
  772.                 // 0xff Error packet
  773.                 $buf substr ($buf1);
  774.  
  775.                 $tmp unpack ('v'substr ($buf02));
  776.                 $r->errono $tmp[1];
  777.                 $r->sqlstate_mark $buf[2];
  778.                 $r->sqlsate substr ($buf35);
  779.                 $r->message substr ($buf8);
  780.  
  781.                 return self::MYSQL_RET_ERROR;
  782.                 break;
  783.             default:
  784.                 return self::MYSQL_RET_QUERY;
  785.         }
  786.     // }}}
  787.  
  788.     // {{{ private (binary) sThread_MYSQL::query_packet ($type, $arg)
  789.     private function query_packet ($type$arg{
  790.         $arg preg_replace ('/;$/'''$arg);
  791.  
  792.         $s pack ('c'$type);
  793.         $s .= $arg;
  794.  
  795.         $send pack ('Sxc'strlen ($s)0x00$s;
  796.         return $send;
  797.     // }}}
  798.  
  799.     // {{{ private (binary) sThread_MYSQL::quit_packet ()
  800.     private function quit_packet ({
  801.         $send pack ('c*'0x010x000x000x000x01);
  802.         return $send;
  803.     // }}}
  804. }
  805.  
  806. ?>

Documentation generated on Tue, 14 May 2019 02:00:38 +0900 by phpDocumentor 1.4.4