Advertisement
Ostap34PHP

Untitled

Jun 17th, 2018
254
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 13.18 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4.  * Класс для доступа к базе данных
  5.  *
  6.  * @copyright   2013 Denis Pikusov
  7.  * @link        http://simplacms.ru
  8.  * @author      Denis Pikusov
  9.  *
  10.  */
  11.  
  12. require_once('Simpla.php');
  13.  
  14. class Database extends Simpla
  15. {
  16.     private $mysqli;
  17.     private $res;
  18.  
  19.     /**
  20.      * В конструкторе подключаем базу
  21.      */
  22.     public function __construct()
  23.     {
  24.         parent::__construct();
  25.         $this->connect();
  26.     }
  27.  
  28.     /**
  29.      * В деструкторе отсоединяемся от базы
  30.      */
  31.     public function __destruct()
  32.     {
  33.         $this->disconnect();
  34.     }
  35.  
  36.     /**
  37.      * Подключение к базе данных
  38.      */
  39.     public function connect()
  40.     {
  41.         // При повторном вызове возвращаем существующий линк
  42.         if(!empty($this->mysqli))
  43.             return $this->mysqli;
  44.         // Иначе устанавливаем соединение
  45.         else
  46.             $this->mysqli = new mysqli($this->config->db_server, $this->config->db_user, $this->config->db_password, $this->config->db_name);
  47.        
  48.         // Выводим сообщение, в случае ошибки
  49.         if($this->mysqli->connect_error)
  50.         {
  51.             trigger_error("Could not connect to the database: ".$this->mysqli->connect_error, E_USER_WARNING);
  52.             return false;
  53.         }
  54.         // Или настраиваем соединение
  55.         else
  56.         {
  57.             if($this->config->db_charset)
  58.                 $this->mysqli->query('SET NAMES '.$this->config->db_charset);      
  59.             if($this->config->db_sql_mode)     
  60.                 $this->mysqli->query('SET SESSION SQL_MODE = "'.$this->config->db_sql_mode.'"');
  61.             if($this->config->db_timezone)
  62.                 $this->mysqli->query('SET time_zone = "'.$this->config->db_timezone.'"');
  63.         }
  64.         return $this->mysqli;
  65.     }
  66.  
  67.     /**
  68.      * Закрываем подключение к базе данных
  69.      */
  70.     public function disconnect()
  71.     {
  72.         if(!@$this->mysqli->close())
  73.             return true;
  74.         else
  75.             return false;
  76.     }
  77.    
  78.  
  79.     /**
  80.      * Запрос к базе. Обазятелен первый аргумент - текст запроса.
  81.      * При указании других аргументов автоматически выполняется placehold() для запроса с подстановкой этих аргументов
  82.      */
  83.     public function query()
  84.     {
  85.         if(is_object($this->res))
  86.             $this->res->free();
  87.            
  88.         $args = func_get_args();
  89.         $q = call_user_func_array(array($this, 'placehold'), $args);       
  90.         return $this->res = $this->mysqli->query($q);
  91.     }
  92.    
  93.  
  94.     /**
  95.      *  Экранирование
  96.      */
  97.     public function escape($str)
  98.     {
  99.         return $this->mysqli->real_escape_string($str);
  100.     }
  101.  
  102.    
  103.     /**
  104.      * Плейсхолдер для запросов. Пример работы: $query = $db->placehold('SELECT name FROM products WHERE id=?', $id);
  105.      */
  106.     public function placehold()
  107.     {
  108.         $args = func_get_args();   
  109.         $tmpl = array_shift($args);
  110.         // Заменяем все __ на префикс, но только необрамленные кавычками
  111.         $tmpl = preg_replace('/([^"\'0-9a-z_])__([a-z_]+[^"\'])/i', "\$1".$this->config->db_prefix."\$2", $tmpl);
  112.         if(!empty($args))
  113.         {
  114.             $result = $this->sql_placeholder_ex($tmpl, $args, $error);
  115.             if ($result === false)
  116.             {
  117.                 $error = "Placeholder substitution error. Diagnostics: \"$error\"";
  118.                 trigger_error($error, E_USER_WARNING);
  119.                 return false;
  120.             }
  121.             return $result;
  122.         }
  123.         else
  124.             return $tmpl;
  125.     }
  126.    
  127.  
  128.     /**
  129.      * Возвращает результаты запроса. Необязательный второй аргумент указывает какую колонку возвращать вместо всего массива колонок
  130.      */
  131.     public function results($field = null)
  132.     {
  133.         $results = array();
  134.         if(!$this->res)
  135.         {
  136.             trigger_error($this->mysqli->error, E_USER_WARNING);
  137.             return false;
  138.         }
  139.  
  140.         if($this->res->num_rows == 0)
  141.             return array();
  142.  
  143.         while($row = $this->res->fetch_object())
  144.         {
  145.             if(!empty($field) && isset($row->$field))
  146.                 array_push($results, $row->$field);            
  147.             else
  148.                 array_push($results, $row);
  149.         }
  150.         return $results;
  151.     }
  152.  
  153.     /**
  154.      * Возвращает первый результат запроса. Необязательный второй аргумент указывает какую колонку возвращать вместо всего массива колонок
  155.      */
  156.     public function result($field = null)
  157.     {
  158.         $result = array();
  159.         if(!$this->res)
  160.         {
  161.             $this->error_msg = "Could not execute query to database";
  162.             return 0;
  163.         }
  164.         $row = $this->res->fetch_object();
  165.         if(!empty($field) && isset($row->$field))
  166.             return $row->$field;
  167.         elseif(!empty($field) && !isset($row->$field))
  168.             return false;
  169.         else
  170.             return $row;
  171.     }
  172.  
  173.     /**
  174.      * Возвращает последний вставленный id
  175.      */
  176.     public function insert_id()
  177.     {
  178.         return $this->mysqli->insert_id;
  179.     }
  180.  
  181.     /**
  182.      * Возвращает количество выбранных строк
  183.      */
  184.     public function num_rows()
  185.     {
  186.         return $this->res->num_rows;
  187.     }
  188.  
  189.     /**
  190.      * Возвращает количество затронутых строк
  191.      */
  192.     public function affected_rows()
  193.     {
  194.         return $this->mysqli->affected_rows;
  195.     }
  196.    
  197.     /**
  198.      * Компиляция плейсхолдера
  199.      */
  200.     private function sql_compile_placeholder($tmpl)
  201.     {
  202.         $compiled = array();
  203.         $p = 0;  // текущая позиция в строке
  204.         $i = 0;  // счетчик placeholder-ов
  205.         $has_named = false;
  206.         while(false !== ($start = $p = strpos($tmpl, "?", $p)))
  207.         {
  208.             // Определяем тип placeholder-а.
  209.             switch ($c = substr($tmpl, ++$p, 1))
  210.             {
  211.                 case '%': case '@': case '#':
  212.                     $type = $c; ++$p; break;
  213.                 default:
  214.                     $type = ''; break;
  215.             }
  216.             // Проверяем, именованный ли это placeholder: "?keyname"
  217.             if (preg_match('/^((?:[^\s[:punct:]]|_)+)/', substr($tmpl, $p), $pock))
  218.             {
  219.                 $key = $pock[1];
  220.                 if ($type != '#')
  221.                     $has_named = true;
  222.                 $p += strlen($key);
  223.             }
  224.             else
  225.             {
  226.                 $key = $i;
  227.                 if ($type != '#')
  228.                     $i++;
  229.             }
  230.             // Сохранить запись о placeholder-е.
  231.             $compiled[] = array($key, $type, $start, $p - $start);
  232.         }
  233.         return array($compiled, $tmpl, $has_named);
  234.     }
  235.  
  236.     /**
  237.      * Выполнение плейсхолдера
  238.      */
  239.     private function sql_placeholder_ex($tmpl, $args, &$errormsg)
  240.     {
  241.         // Запрос уже разобран?.. Если нет, разбираем.
  242.         if (is_array($tmpl))
  243.             $compiled = $tmpl;
  244.         else
  245.             $compiled    = $this->sql_compile_placeholder($tmpl);
  246.    
  247.         list ($compiled, $tmpl, $has_named) = $compiled;
  248.    
  249.         // Если есть хотя бы один именованный placeholder, используем
  250.         // первый аргумент в качестве ассоциативного массива.
  251.         if ($has_named)
  252.             $args = @$args[0];
  253.    
  254.         // Выполняем все замены в цикле.
  255.         $p   = 0;               // текущее положение в строке
  256.         $out = '';          // результирующая строка
  257.         $error = false; // были ошибки?
  258.    
  259.         foreach ($compiled as $num=>$e)
  260.         {
  261.             list ($key, $type, $start, $length) = $e;
  262.    
  263.             // Pre-string.
  264.             $out .= substr($tmpl, $p, $start - $p);
  265.             $p = $start + $length;
  266.    
  267.             $repl = '';     // текст для замены текущего placeholder-а
  268.             $errmsg = ''; // сообщение об ошибке для этого placeholder-а
  269.             do {
  270.                 // Это placeholder-константа?
  271.                 if ($type === '#')
  272.                 {
  273.                     $repl = @constant($key);
  274.                     if (NULL === $repl)  
  275.                         $error = $errmsg = "UNKNOWN_CONSTANT_$key";
  276.                     break;
  277.                 }
  278.                 // Обрабатываем ошибку.
  279.                 if (!isset($args[$key]))
  280.                 {
  281.                     $error = $errmsg = "UNKNOWN_PLACEHOLDER_$key";
  282.                     break;
  283.                 }
  284.                 // Вставляем значение в соответствии с типом placeholder-а.
  285.                 $a = $args[$key];
  286.                 if ($type === '')
  287.                 {
  288.                     // Скалярный placeholder.
  289.                     if (is_array($a))
  290.                     {
  291.                         $error = $errmsg = "NOT_A_SCALAR_PLACEHOLDER_$key";
  292.                         break;
  293.                     }
  294.                     $repl = is_int($a) || is_float($a) ? str_replace(',', '.', $a) : "'".addslashes($a)."'";
  295.                     break;
  296.                 }
  297.                 // Иначе это массив или список.
  298.                 if(is_object($a))
  299.                     $a = get_object_vars($a);
  300.                
  301.                 if (!is_array($a))
  302.                 {
  303.                     $error = $errmsg = "NOT_AN_ARRAY_PLACEHOLDER_$key";
  304.                     break;
  305.                 }
  306.                 if ($type === '@')
  307.                 {
  308.                     // Это список.
  309.                     foreach ($a as $v)
  310.                     {
  311.                         if(is_null($v))
  312.                             $r = "NULL";
  313.                         else
  314.                             $r = "'".@addslashes($v)."'";
  315.  
  316.                         $repl .= ($repl===''? "" : ",").$r;
  317.                     }
  318.                 }
  319.                 elseif ($type === '%')
  320.                 {
  321.                     // Это набор пар ключ=>значение.
  322.                     $lerror = array();
  323.                     foreach ($a as $k=>$v)
  324.                     {
  325.                         if (!is_string($k))
  326.                             $lerror[$k] = "NOT_A_STRING_KEY_{$k}_FOR_PLACEHOLDER_$key";
  327.                         else
  328.                             $k = preg_replace('/[^a-zA-Z0-9_]/', '_', $k);
  329.  
  330.                         if(is_null($v))
  331.                             $r = "=NULL";
  332.                         else
  333.                             $r = "='".@addslashes($v)."'";
  334.  
  335.                         $repl .= ($repl===''? "" : ", ").$k.$r;
  336.                     }
  337.                     // Если была ошибка, составляем сообщение.
  338.                     if (count($lerror))
  339.                     {
  340.                         $repl = '';
  341.                         foreach ($a as $k=>$v)
  342.                         {
  343.                             if (isset($lerror[$k]))
  344.                             {
  345.                                 $repl .= ($repl===''? "" : ", ").$lerror[$k];
  346.                             }
  347.                             else
  348.                             {
  349.                                 $k = preg_replace('/[^a-zA-Z0-9_-]/', '_', $k);
  350.                                 $repl .= ($repl===''? "" : ", ").$k."=?";
  351.                             }
  352.                         }
  353.                         $error = $errmsg = $repl;
  354.                     }
  355.                 }
  356.             } while (false);
  357.             if ($errmsg) $compiled[$num]['error'] = $errmsg;
  358.             if (!$error) $out .= $repl;
  359.         }
  360.         $out .= substr($tmpl, $p);
  361.    
  362.         // Если возникла ошибка, переделываем результирующую строку
  363.         // в сообщение об ошибке (расставляем диагностические строки
  364.         // вместо ошибочных placeholder-ов).
  365.         if ($error)
  366.         {
  367.             $out = '';
  368.             $p   = 0; // текущая позиция
  369.             foreach ($compiled as $num=>$e)
  370.             {
  371.                 list ($key, $type, $start, $length) = $e;
  372.                 $out .= substr($tmpl, $p, $start - $p);
  373.                 $p = $start + $length;
  374.                 if (isset($e['error']))
  375.                 {
  376.                     $out .= $e['error'];
  377.                 }
  378.                 else
  379.                 {
  380.                     $out .= substr($tmpl, $start, $length);
  381.                 }
  382.             }
  383.             // Последняя часть строки.
  384.             $out .= substr($tmpl, $p);
  385.             $errormsg = $out;
  386.             return false;
  387.         }
  388.         else
  389.         {
  390.             $errormsg = false;
  391.             return $out;
  392.         }
  393.     }
  394.  
  395.     public function dump($filename)
  396.     {
  397.         $h = fopen($filename, 'w');
  398.         $q = $this->placehold("SHOW FULL TABLES LIKE '__%';");     
  399.         $result = $this->mysqli->query($q);
  400.         while($row = $result->fetch_row())
  401.         {
  402.             if($row[1] == 'BASE TABLE')
  403.                 $this->dump_table($row[0], $h);
  404.         }
  405.         fclose($h);
  406.     }
  407.    
  408.     function restore($filename)
  409.     {
  410.         $templine = '';
  411.         $h = fopen($filename, 'r');
  412.    
  413.         // Loop through each line
  414.         if($h)
  415.         {
  416.             while(!feof($h))
  417.             {
  418.                 $line = fgets($h);
  419.                 // Only continue if it's not a comment
  420.                 if (substr($line, 0, 2) != '--' && $line != '')
  421.                 {
  422.                     // Add this line to the current segment
  423.                     $templine .= $line;
  424.                     // If it has a semicolon at the end, it's the end of the query
  425.                     if (substr(trim($line), -1, 1) == ';')
  426.                     {
  427.                         // Perform the query
  428.                         $this->mysqli->query($templine) or print('Error performing query \'<b>'.$templine.'</b>\': '.$this->mysqli->error.'<br/><br/>');
  429.                         // Reset temp variable to empty
  430.                         $templine = '';
  431.                     }
  432.                 }
  433.             }
  434.         }
  435.         fclose($h);
  436.     }
  437.    
  438.    
  439.     private function dump_table($table, $h)
  440.     {
  441.         $sql = "SELECT * FROM `$table`;";
  442.         $result = $this->mysqli->query($sql);
  443.         if($result)
  444.         {
  445.             fwrite($h, "/* Data for table $table */\n");
  446.             fwrite($h, "TRUNCATE TABLE `$table`;\n");
  447.            
  448.             $num_rows = $result->num_rows;
  449.             $num_fields = $this->mysqli->field_count;
  450.    
  451.             if($num_rows > 0)
  452.             {
  453.                 $field_type=array();
  454.                 $field_name = array();
  455.                 $meta = $result->fetch_fields();
  456.                 foreach($meta as $m)
  457.                 {
  458.                     array_push($field_type, $m->type);
  459.                     array_push($field_name, $m->name);
  460.                 }
  461.                 $fields = implode('`, `', $field_name);
  462.                 fwrite($h,  "INSERT INTO `$table` (`$fields`) VALUES\n");
  463.                 $index=0;
  464.                 while( $row = $result->fetch_row())
  465.                 {
  466.                     fwrite($h, "(");
  467.                     for( $i=0; $i < $num_fields; $i++)
  468.                     {
  469.                         if( is_null( $row[$i]))
  470.                             fwrite($h, "null");
  471.                         else
  472.                         {
  473.                             switch( $field_type[$i])
  474.                             {
  475.                                 case 'int':
  476.                                     fwrite($h,  $row[$i]);
  477.                                     break;
  478.                                 case 'string':
  479.                                 case 'blob' :
  480.                                 default:
  481.                                     fwrite($h, "'". $this->mysqli->real_escape_string($row[$i])."'");
  482.    
  483.                             }
  484.                         }
  485.                         if( $i < $num_fields-1)
  486.                             fwrite($h,  ",");
  487.                     }
  488.                     fwrite($h, ")");
  489.    
  490.                     if( $index < $num_rows-1)
  491.                         fwrite($h,  ",");
  492.                     else
  493.                         fwrite($h, ";");
  494.                     fwrite($h, "\n");
  495.    
  496.                     $index++;
  497.                 }
  498.             }
  499.             $result->free();
  500.         }
  501.         fwrite($h, "\n");
  502.     }
  503. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement