Пробую:
$db = $this->db->query('SLECT name, value FROM table WHERE id = ? AND name =?', 1 , 2);
Выдает мне:
Number of variables doesn't match number of parameters in prepared statement
Пришло 3 аргумента, а ушел массив параметров из 2х аргументов.
Как быть?
и что в ней удивительного? чистый mysql умеет так же
Понятно, что и с обычными запросами тоже можно работат, без плейсхолдеров. Но именно в данной реализации нравятся плейсхолдеры. Посмотрел подобные библиотеки, мало их, и все не то. Хотелось бы что-то подобное.
<?php
require_once('System.php');
class Database extends System
{
private $mysqli;
private $res;
public function __construct()
{
parent::__construct();
$this->connect();
}
public function __destruct()
{
$this->disconnect();
}
public function connect()
{
if (!empty($this->mysqli))
return $this->mysqli;
else
$this->mysqli = new mysqli($this->config->db_server, $this->config->db_user, $this->config->db_password, $this->config->db_name);
if ($this->mysqli->connect_error) {
trigger_error("Не удалось подключиться к базе данных: " . $this->mysqli->connect_error, E_USER_WARNING);
return false;
} else {
if ($this->config->db_charset)
$this->mysqli->query('SET NAMES ' . $this->config->db_charset);
if ($this->config->db_sql_mode)
$this->mysqli->query('SET SESSION SQL_MODE = "' . $this->config->db_sql_mode . '"');
if ($this->config->db_timezone)
$this->mysqli->query('SET time_zone = "' . $this->config->db_timezone . '"');
}
return $this->mysqli;
}
public function disconnect()
{
if (!@$this->mysqli->close())
return true;
else
return false;
}
public function query()
{
if (is_object($this->res))
$this->res->free();
$args = func_get_args();
$q = call_user_func_array(array(
$this,
'placehold'
), $args);
return $this->res = $this->mysqli->query($q);
}
public function escape($str)
{
return $this->mysqli->real_escape_string($str);
}
public function placehold()
{
$args = func_get_args();
$tmpl = array_shift($args);
$tmpl = preg_replace('/([^"\'0-9a-z_])__([a-z_]+[^"\'])/i', "\$1" . $this->config->db_prefix . "\$2", $tmpl);
if (!empty($args)) {
$result = $this->sql_placeholder_ex($tmpl, $args, $error);
if ($result === false) {
$error = "Ошибка: \"$error\"";
trigger_error($error, E_USER_WARNING);
return false;
}
return $result;
} else
return $tmpl;
}
public function results($field = null)
{
$results = array();
if (!$this->res) {
trigger_error($this->mysqli->error, E_USER_WARNING);
return false;
}
if ($this->res->num_rows == 0)
return array();
while ($row = $this->res->fetch_object()) {
if (!empty($field) && isset($row->$field))
array_push($results, $row->$field);
else
array_push($results, $row);
}
return $results;
}
public function result($field = null)
{
$result = array();
if (!$this->res) {
$this->error_msg = "Не удалось выполнить запрос к базе данных";
return 0;
}
$row = $this->res->fetch_object();
if (!empty($field) && isset($row->$field))
return $row->$field;
elseif (!empty($field) && !isset($row->$field))
return false;
else
return $row;
}
public function insert_id()
{
return $this->mysqli->insert_id;
}
public function num_rows()
{
return $this->res->num_rows;
}
public function affected_rows()
{
return $this->mysqli->affected_rows;
}
private function sql_compile_placeholder($tmpl)
{
$compiled = array();
$p = 0;
$i = 0;
$has_named = false;
while (false !== ($start = $p = strpos($tmpl, "?", $p))) {
switch ($c = substr($tmpl, ++$p, 1)) {
case '%':
case '@':
case '#':
$type = $c;
++$p;
break;
default:
$type = '';
break;
}
if (preg_match('/^((?:[^\s[:punct:]]|_)+)/', substr($tmpl, $p), $pock)) {
$key = $pock[1];
if ($type != '#')
$has_named = true;
$p += strlen($key);
} else {
$key = $i;
if ($type != '#')
$i++;
}
$compiled[] = array(
$key,
$type,
$start,
$p - $start
);
}
return array(
$compiled,
$tmpl,
$has_named
);
}
private function sql_placeholder_ex($tmpl, $args, &$errormsg)
{
if (is_array($tmpl))
$compiled = $tmpl;
else
$compiled = $this->sql_compile_placeholder($tmpl);
list($compiled, $tmpl, $has_named) = $compiled;
if ($has_named)
$args = @$args[0];
$p = 0;
$out = '';
$error = false;
foreach ($compiled as $num => $e) {
list($key, $type, $start, $length) = $e;
$out .= substr($tmpl, $p, $start - $p);
$p = $start + $length;
$repl = '';
$errmsg = '';
do {
if ($type === '#') {
$repl = @constant($key);
if (NULL === $repl)
$error = $errmsg = "UNKNOWN_CONSTANT_$key";
break;
}
if (!isset($args[$key])) {
$error = $errmsg = "UNKNOWN_PLACEHOLDER_$key";
break;
}
$a = $args[$key];
if ($type === '') {
if (is_array($a)) {
$error = $errmsg = "NOT_A_SCALAR_PLACEHOLDER_$key";
break;
}
$repl = is_int($a) || is_float($a) ? str_replace(',', '.', $a) : "'" . addslashes($a) . "'";
break;
}
if (is_object($a))
$a = get_object_vars($a);
if (!is_array($a)) {
$error = $errmsg = "NOT_AN_ARRAY_PLACEHOLDER_$key";
break;
}
if ($type === '@') {
foreach ($a as $v) {
if (is_null($v))
$r = "NULL";
else
$r = "'" . @addslashes($v) . "'";
$repl .= ($repl === '' ? "" : ",") . $r;
}
} elseif ($type === '%') {
$lerror = array();
foreach ($a as $k => $v) {
if (!is_string($k))
$lerror[$k] = "NOT_A_STRING_KEY_{$k}_FOR_PLACEHOLDER_$key";
else
$k = preg_replace('/[^a-zA-Z0-9_]/', '_', $k);
if (is_null($v))
$r = "=NULL";
else
$r = "='" . @addslashes($v) . "'";
$repl .= ($repl === '' ? "" : ", ") . $k . $r;
}
if (count($lerror)) {
$repl = '';
foreach ($a as $k => $v) {
if (isset($lerror[$k])) {
$repl .= ($repl === '' ? "" : ", ") . $lerror[$k];
} else {
$k = preg_replace('/[^a-zA-Z0-9_-]/', '_', $k);
$repl .= ($repl === '' ? "" : ", ") . $k . "=?";
}
}
$error = $errmsg = $repl;
}
}
} while (false);
if ($errmsg)
$compiled[$num]['error'] = $errmsg;
if (!$error)
$out .= $repl;
}
$out .= substr($tmpl, $p);
if ($error) {
$out = '';
$p = 0;
foreach ($compiled as $num => $e) {
list($key, $type, $start, $length) = $e;
$out .= substr($tmpl, $p, $start - $p);
$p = $start + $length;
if (isset($e['error'])) {
$out .= $e['error'];
} else {
$out .= substr($tmpl, $start, $length);
}
}
$out .= substr($tmpl, $p);
$errormsg = $out;
return false;
} else {
$errormsg = false;
return $out;
}
}
public function dump($filename)
{
$h = fopen($filename, 'w');
$q = $this->placehold("SHOW FULL TABLES LIKE '__%';");
$result = $this->mysqli->query($q);
while ($row = $result->fetch_row()) {
if ($row[1] == 'BASE TABLE')
$this->dump_table($row[0], $h);
}
fclose($h);
}
function restore($filename)
{
$templine = '';
$h = fopen($filename, 'r');
if ($h) {
while (!feof($h)) {
$line = fgets($h);
if (substr($line, 0, 2) != '--' && $line != '') {
$templine .= $line;
if (substr(trim($line), -1, 1) == ';') {
$this->mysqli->query($templine) or print('Ошибка выполнения запроса \'<b>' . $templine . '</b>\': ' . $this->mysqli->error . '<br/><br/>');
$templine = '';
}
}
}
}
fclose($h);
}
private function dump_table($table, $h)
{
$sql = "SELECT * FROM `$table`;";
$result = $this->mysqli->query($sql);
if ($result) {
fwrite($h, "/* Data for table $table */\n");
fwrite($h, "TRUNCATE TABLE `$table`;\n");
$num_rows = $result->num_rows;
$num_fields = $this->mysqli->field_count;
if ($num_rows > 0) {
$field_type = array();
$field_name = array();
$meta = $result->fetch_fields();
foreach ($meta as $m) {
array_push($field_type, $m->type);
array_push($field_name, $m->name);
}
$fields = implode('`, `', $field_name);
fwrite($h, "INSERT INTO `$table` (`$fields`) VALUES\n");
$index = 0;
while ($row = $result->fetch_row()) {
fwrite($h, "(");
for ($i = 0; $i < $num_fields; $i++) {
if (is_null($row[$i]))
fwrite($h, "null");
else {
switch ($field_type[$i]) {
case 'int':
fwrite($h, $row[$i]);
break;
case 'string':
case 'blob':
default:
fwrite($h, "'" . $this->mysqli->real_escape_string($row[$i]) . "'");
}
}
if ($i < $num_fields - 1)
fwrite($h, ",");
}
fwrite($h, ")");
if ($index < $num_rows - 1)
fwrite($h, ",");
else
fwrite($h, ";");
fwrite($h, "\n");
$index++;
}
}
$result->free();
}
fwrite($h, "\n");
}
}
Примеры запросов:
.... $db->placehold(SELECT * FROM __table WHERE id = ? AND name = ?, 1, Misha);
.... $db->placehold(SELECT * FROM __cities WHERE region_id = ?, array('id' = 1, 'id' = 2));
$tpl_module->set('{menu}',isset($tpl_module->result['a']) ? $tpl_module->result['a']:null);//Вывод меню и их подменю
$tpl_module->compile('content');
На выходе:
# Главная
# Новости > Зарубежные
> Спортивные
> Еще
# Тестовое меню > Зарубежные
> Спортивные
> Еще
> Еще 2
> Еще 3
Почему-то данные дублируются.. (отмечено красным)
Нафига поле id? Оно лишнее, category_id и property_id более чем достаточно и являются хорошим первичным ключом. Плюс индекс по property_id для обратного поиска.
Пишу тупо файл в котором четыре переменных для БД.
Затем выполняю include_once(); и подключаю этот файл в другой, где создаю PDO.
В итоге все подключается но выдает ошибку Undefined variable: db_host и для всех остальных переменных тоже.
Имена переменных не перепутаны
Файл точно подключается
Пробовал из разных мест, не отрабатывает даже если файлы в одном каталоге.
Единственное, что приходит в голову, что может где какие-то права нужно настраивать?
Пользуюсь xampp на windows,
Спасите кто-нибудь, а то как-то не знаю куда копать. Заранее спасибо большое.
E_NOTICE - замечания Notice: Undefined variable - не критично, курим в сторону isset(); - должно вылечить.
+Можно убрать ошибки с помощью
in_array(array('id' => $row['id']), $diff) - я так понимаю это сопли, как их убрать так и не понял, но - работает! Может у кого есть идеи? Или я что-то не доглядел.
Спасибо за ответы, подсмотрел реализацию в cms simpla. Но всплывает ещё вопрос. Как вывести все доп свойства в каталог? Причём сделать это красиво.
В симпла выводится так:
--- цикл ---
название товара
картинка
цена
--- конец цикла ---
(Название, картинка, цена - отдельные поля в таблице товаров, т.е не доп свойства, в шаблон каталога можно вывести как нужно, т.е:
$tpl->set('{name}', $row['name']) и так далее, но как быть с доп свойствами? Таким же макаром хочу их вывести в шаблон каталога, дабы можно было их красиво расположить, а не просто кучей вывести.
В симпле конечно хорошо и красиво все оформлено в каталоге для продаж техники и прочего, но как быть с недвижимостью? Помимо картинки и цены есть ещё и адреса, планировки, кол-во комнат и т.д. все это будет в свойствах (аттрибутах).
Если дергать свойства для каждого объекта в каталоге, то лично у меня получается так:
(Пример на колене)
$sql="Select * from attributes where realty_id = $row['id']";
foreach($sqlas$attr){
$attr.=$attr['name']
}
В шаблон атрибуты (свойства) вывожу так:
$tpl->set('{attributes}', $attr);
Но все свойства будут в куче один за другим, т.е расположить в шаблоне их не получится, т.к выводится все в {attributes}.