MySql проблемы сортировки utf-8

Столкнулся с проблемой: на локальной машине, все сортируется нормально. А вот как только тестирование начинается на сервере — сортировка русских слов и фраз идёт не верным путем.
Начал разбираться. Хоть таблицы и в utf8_general_ci, но сервер настроен на latin1.
В принципе легко посмотреть с какой стороны подходить, достаточно зайти в базу и посмотреть в читабельном виде наши данные или нет. Если нет — нужно прописывать перекодировку на utf-8 в скрипте, после подключения к бд.

        $this->getAdapter()->query("SET NAMES utf8");
        $this->getAdapter()->query("SET collation_connection=utf8_general_ci");
        $this->getAdapter()->query("SET collation_server=utf8_general_ci");
        $this->getAdapter()->query("SET character_set_client=utf8");
        $this->getAdapter()->query("SET character_set_connection=utf8");
        $this->getAdapter()->query("SET character_set_results=utf8");
        $this->getAdapter()->query("SET character_set_server=utf8");

PS: $this->getAdapter()->query = mysql_query.

Для Zend Franework: application.ini

resources.db.params.charset = "utf8"
resources.db.params.driver_options.1002 = "SET NAMES utf8"

Но, после этого, на сайте у нас произойдет ужас с кодировкой. И для этого данные в базе нужно из latin1 перекодировать в UTF-8.
Так, а что же делать с данными, которыми у нас наполнен сайт? Не вбивать же всё вручную. Нашел очень удобную панель управления базой — Sypex Dumper. Очень приятно, что разработали это украинские ребята.
Так вот, делаем экспорт с помощью Sypex Dumper, установив в кодировке latin1 и жмем выполнить.

После выполнения качаем бэк-ап и открываем в редакторе. Если все правильно сделали — получим читаемый текст. Дальше, этот бэк-ап восстанавливаем в базу, чтобы все было хорошо с кодировочкой.

PHP Класс каталога

Простой класс для каталога товаров


<?php
 require_once "config/db.php";
 require_once "product.php";

 // Класс для работы с каталогом

 class Catalog{

 var $maincat;
 var $subcat;

 // фильтры
 var $brand ;
 var $page;
 var $price;

 protected $count = 0;
 protected $breadcrumbs = "";

 protected $query;
 //protected $page_query;

 function __construct($event, $maincat, $subcat, $brand, $price){

 // Анти-лох
 $maincat = preg_replace("/\D/","",$maincat);
 $subcat = preg_replace("/\D/","",$subcat);
 $brand = preg_replace("/\D/","",$brand);
 /*$page = preg_replace("/\D/","",$page);

 if ((!$page)||($page < 1)) $page = 1;*/
 ///////////////////////////////////////////////

 // Как работать с набором? непонятно
 $query = "SELECT * FROM `goods` WHERE 1=1 ";

 if ($maincat > 0){
 $query .=" AND `mcid`='".$maincat."' ";
 }
 if ($subcat > 0){
 $query .=" AND `sbid`='".$subcat."' ";
 }
 if ($brand > 0){
 $query .=" AND `bid`='".$brand."' ";
 }

 if ($event){

 $q = "SELECT id FROM napravl WHERE en Like '%".$event."%' Limit 1";

 $r = mysql_query($q);
 if (!$r){
 Error::Get_Mess("Ошибка работы БД");
 }

 if (@mysql_numrows($r)<1){
 Error::Get_Mess("Ивента нет");
 }

 $data = mysql_fetch_array($r);

 $query .= " AND nid Like '%".$data['id']."%'";

 }

 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ДОБАВИТЬ ФИЛЬТР ПО ЦЕНЕ !!!!!!!!!!!!!!!!!!!!!!!!!!!!
 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ДОБАВИТЬ ФИЛЬТР ПО НАПРАВЛЕНИЮ !!!!!!!!!!!!!!!!!!!!!!!!!!!!

 $this->query = $query;

 }

 // Хлебные крошки
 function show_breadcrumbs($maincat, $subcat,  $event){
 $maincat = preg_replace("/\D/","",$maincat); // id гланой категории
 $subcat = preg_replace("/\D/","",$subcat); // id подкатегории

 $breadcrumbs = '<a href="/catalog/"> Каталог </a>';

 if ($subcat > 0){
 // Есть подкатегория - она активная
 $q =  "SELECT main_cat.name AS mname, sub_cat.name AS sname,
 main_cat.id AS mid, sub_cat.id AS sid
 FROM main_cat
 INNER JOIN sub_cat ON sub_cat.id = '".$subcat."'
 AND sub_cat.mcid = '".$maincat."'
 WHERE main_cat.id = '".$maincat."' Limit 1";
 //        echo $q;
 $r = mysql_query($q);

 if (!$r){
 Error::Get_Mess("Ошибка работы БД");
 }

 if (@mysql_numrows($r)<1){
 //Error::Get_Mess("Ничего не найденно!");
 }

 $data = mysql_fetch_array($r);
 //print_r($data);

 $breadcrumbs .= ' / <a href="/catalog/'.$event.'/'.$data['mid'].'/">'.$data['mname'].'</a> ';
 $breadcrumbs .= ' / <a href="/catalog/'.$event.'/'.$data['mid'].'/'.$data['sid'].'/"><b>'.$data['sname'].'</b></a> ';
 mysql_free_result($r);

 }
 else{
 // подкатегории нет
 $q = "SELECT id, name
 FROM main_cat
 WHERE main_cat.id = '".$maincat."' Limit 1";
 $r = mysql_query($q);

 if (!$r){
 Error::Get_Mess("Ошибка работы БД");
 }

 if (@mysql_numrows($r)<1){
 //Error::Get_Mess("Ничего не найденно!");
 }
 $data = mysql_fetch_array($r);
 $breadcrumbs .= ' / <a href="/catalog/'.$event.'/'.$data['id'].'/">'.$data['name'].'</a> ';

 mysql_free_result($r);
 }

 echo $breadcrumbs;

 }

 // Отображение товара для старницы, на вход идёт номер страницы

 function show_content($page){

 $page = preg_replace("/\D/","",$page);
 if ((!$page)||($page < 1)) $page = 1;

 // Формируем запрос согласно отображаемой страницы
 $query = $this->query;
 if ($page == 1){
 $query .= " LIMIT 0, 9";
 }
 else{
 $query .= " LIMIT ".(($page-1)*9).",9 ";
 }
 //////////////////////////////////////////////////
 $r = mysql_query($query);

 if (!$r){
 Error::Get_Mess("Ошибка работы БД");

 //__halt_compiler();
 }

 // Вывод результата

 if (@mysql_num_rows($r)==0){
 Error::Get_Mess("Нет товаров по данным критериям");
 }
 else{
 while ($row = mysql_fetch_object($r)){
 $count++;
 // Разбиение на три столбца
 if ($count >3 ){
 echo "<br /><br/>";
 $count=0;
 }
 echo "<hr>";
 $product = new Product($row->id);
 // Имя
 $product -> Get_Name();
 echo "<br />";
 // Короткое описание
 $product -> Get_Short_D();
 echo "<br />";
 // Полное описание
 $product -> Get_Full_D();
 echo "<br />";
 // Цена в формате 12.00 грн.
 $product -> Get_Price();
 echo "<br />";
 // Добавить в список
 $product -> Add_To_List();
 // Получить бренд
 $product->Get_Brand();

 }
 }
 mysql_free_result($r);
 //echo $query;
 }

 // Пагинатор
 function show_paginator($cur_page,$txt){
 // $txt - УРИ
 echo "<br /><hr>";

 $page = preg_replace("/\D/","",$cur_page);
 $num_page = $page;
 if ((!$page)||($page < 1)) $page = 1;
 //////////////////////////////////////

 // количество на страницу
 $per_page=9;
 $handle = mysql_query($this->query);
 $tmp[0]=mysql_num_rows($handle);
 if ($num_page==1)$to=1;
 $page = $num_page;
 $pages=ceil($tmp[0]/$per_page);
 if ($pages>1){
 if (($page-1)<1)$z=1;
 else $z=$page-1;
 $nx=$page-1;
 if ($nx>0)

//    echo '<a href="controller/show_catalog.php?route=catalog&current_page='.$nx.'">'.$nx.'</a> ';
 if ($nx>0){ echo"&nbsp;<a href='".$txt."page1'><noindex>Первая</noindex></a>&nbsp;&nbsp;";
 echo "&nbsp;&nbsp;<a href='".$txt."page".$nx."'><noindex>Предыдущая</noindex></a>&nbsp;";
 }
 $k=0;
 for ($i=$z;$i<=$pages;$i++){
 $d=$i;
 $k++;
 if ($k==4){
 break;
 }
 if ($d==$page)
 echo '<a><b><noindex>'.$d.'</noindex></b></a>';
 else
 echo"&nbsp;<a href='".$txt."page".$d."'><noindex>$d</noindex></a>&nbsp;";
 }
 $nx=$page+1;
 if ($nx<=$pages)
 echo "&nbsp;<a href='".$txt."page".$nx."'><noindex>Следующая</noindex></a>&nbsp;";
 if ($page<>$pages)
 //Последняя
 echo"&nbsp;&nbsp;<a href='".$txt."page".$pages."'><noindex>Последняя</noindex></a>";
 }
 mysql_free_result($handle);

 }

 function show_subcats($mid, $cur, $event){
 // $cur - активная подкатегория, если есть
 $cur = preg_replace("/\D/","",$cur);
 $mid = preg_replace("/\D/","",$mid);

 if ($mid > 0){
 $q = "SELECT id, name
 FROM sub_cat
 WHERE mcid = '".$mid."'";

 $r = mysql_query($q);

 if (!$r){
 Error::Get_Mess("Ошибка работы БД");

 //__halt_compiler();
 }

 // Вывод результата

 if (@mysql_num_rows($r)==0){
 Error::Get_Mess("Нет подкатегорий по данным критериям");
 }
 else{
 while ($row = mysql_fetch_object($r)){

 // Выводим подкатегории
 echo '&nbsp;<a href="/catalog/'.$event.'/'.$mid.'/'.$row->id.'/"';
 // активная?
 if ($row->id == $cur) echo ' ';
 echo ' >'.$row->name.'</a>&nbsp;';

 }
 }

 }

 else{
 // нет главной категории
 $q = "SELECT id, name
 FROM main_cat";

 $r = mysql_query($q);

 if (!$r){
 Error::Get_Mess("Ошибка работы БД");

 //__halt_compiler();
 }

 // Вывод результата

 if (@mysql_num_rows($r)==0){
 Error::Get_Mess("Нет категорий");
 }
 else{
 while ($row = mysql_fetch_object($r)){

 // Выводим подкатегории
 echo '&nbsp;<a href="/catalog/'.$event.'/'.$row->id.'/"';
 // активная?
 if ($row->id == $cur) echo ' ';
 echo ' >'.$row->name.'</a>&nbsp;';

 }
 }

 }
 }

 // производители
 function Show_Producers($mid,$sid, $event){

 if ($sid > 0){
 $q =  "SELECT name,id FROM `brand` WHERE brand.id IN (
 SELECT bid FROM goods
 WHERE mcid ='".$mid."'
 AND sbid ='".$sid."'
 GROUP BY bid)";
 }
 elseif ($mid > 0){
 $q =  "SELECT name,id FROM `brand` WHERE brand.id IN (
 SELECT bid FROM goods
 WHERE mcid ='".$mid."'
 GROUP BY bid)";

 }
 else {
 $q =  "SELECT name,id FROM `brand` WHERE brand.id IN (
 SELECT bid FROM goods
 GROUP BY bid)";

 }
 $r = mysql_query($q);
 while ($row = mysql_fetch_object($r)){
 if ($mid > 0) {
 echo "<a href='catalog/".$event."/";
 echo $mid."/";
 if ($sid > 0) echo $sid."/";
 echo "brand-".$row->id."' title='".$row->name."'>".trim($row->name)."</a> &nbsp;";
 }
 else{
 // Переход из пустого каталога, мы не знаем какой товар показывать, а пользователь хочет получить товар именно того бренда - логично перекинуть его на карточку Компании.
 require_once "additional.inc";
 echo "<a href='brand/".replace($row->name)."/' title='".$row->name."'>".trim($row->name)."</a> &nbsp;";
 }

 }
 mysql_free_result($r);

 }
}

?>

Класс для товара


<?php

require_once "config/db.php";

 // Класс работы каталога

 class Product{

 var $id;

 //Получаем безопасную переменную
 public function __construct($id){
 $this->id = preg_replace("/\D/","",$id);
 //echo $this->id;
 }

 function Get_Name(){
 $q = "SELECT `name` FROM `goods` WHERE `id`='".$this->id."' Limit 1";
 $r = mysql_query($q);

 if (!$r){
 Error::Get_Mess("Товар не найден!");
 }

 $data = mysql_fetch_array($r);
 echo $data[0];
 mysql_free_result($r);
 }

 // получение краткого описания
 public function Get_Short_D(){
 $q = "SELECT `short_descr` FROM `goods` WHERE `id`='".$this->id."' Limit 1";
 $r = mysql_query($q);

 if (!$r){
 Error::Get_Mess("Товар не найден!");
 }

 $data = mysql_fetch_array($r);
 echo $data[0];
 mysql_free_result($r);
 }

 // Цена
 function Get_Price(){
 $q = "SELECT `short_descr` FROM `goods` WHERE `id`='".$this->id."' Limit 1";
 $r = mysql_query($q);

 if (!$r){
 Error::Get_Mess("Товар не найден!");
 }

 $data = mysql_fetch_array($r);
 printf("%.2f грн.",$data[0]);
 mysql_free_result($r);
 }

 // Добавить в список как заявка
 function Add_To_List(){
 echo "Добавить в список".$this->id;

 }

 // Купить
 function Add_To_Cart(){
 echo "Купить: ".$this->id;

 }

 // Полное описание
 function Get_Full_D(){
 $q = "SELECT `full_descr` FROM `goods` WHERE `id`='".$this->id."' Limit 1";
 $r = mysql_query($q);

 if (!$r){
 Error::Get_Mess("Товар не найден!");
 }

 $data = mysql_fetch_array($r);
 echo $data[0];
 mysql_free_result($r);
 }

 // Получаем бренд
 function Get_Brand(){
 $q = "SELECT name
 FROM brand
 WHERE id = (
 SELECT bid
 FROM goods
 WHERE id='".$this->id."' Limit 1
 ) Limit 1
 ";
 $r = mysql_query($q);

 if (!$r){
 Error::Get_Mess("Бренд не найден!");
 }

 $data = mysql_fetch_array($r);

 // Думаем логически: Если человек тыкает на лого брнеда - он хочет открыть страницу бренда
 require_once "additional.inc";
 echo "<a href='brand/".replace($data[0])."/' title='".$data[0]."'>".trim($data[0])."</a> &nbsp;";

 mysql_free_result($r);
 }

 }

 // На вход подаём id товара

?>

Передача данных из MySQL в checkbox


<?php
 $string = "1/2/3/4/5/6/7/8"; // Строка из базы
 $ar=explode("/",$string);
 print_r($ar);
 ?>

Пишем свой класс для работы PHP с MySQL

Сегодня начнем писать свой класс для работы с базой данных MySQL.
В этих уроках я буду предоставлять «скилеты», которые можно будет дополнить или изменить под свои нужды.

Как всегда, начало будет простым — главное начать, а дальше мы будем усложнять наш класс.
Read more

Индексация в MySQL

Иногда возникает задача хранить какие-то свойства большого количества разнородных объектов, которые никогда не будут участвовать в условиях выборки или сортировке, но которые могут добавляться/исчезать по мере развития сайта. Например, к таким свойствам относятся задаваемые поля профиля пользователя на форуме, настройки сайта в целом, какие-то опции отдельных страниц этого сайта.

В такой ситуации можно использовать универсальную таблиц для всех настроек, которая будет иметь следющую структуру:

type : enum(’user’,’page’,’site’) (признак, кому принадлежит данная настройка: сайту, пользователю или странице, вместо типа enum можно использовать tinyint, чтобы не изменять структуру таблицы, если появятся новые типы объектов),
id : int (идентификатор пользователя или страницы)
name: varchar(24) (название опции)
value: varchar(255) (значение опции).

function get_opt($name,$id=0,$type='site') {
$result=false;
static $cache; // статическая переменная, в которой кешируются свойства
if (!isset($cache[$type.$id])) {
$sql='SELECT name, value FROM options WHERE type="'.$type.'" AND id='.intval($id);
$res=mysql_query($sql);
while ($data=mysql_fetch_row($res)) $cache[$type.$id][$data[0]]=$data[1];
}
return $cache[$type.$id][$name];
}

При этом для эффективной работы такой таблицы нужно учесть одну тонкость: PRIMARY KEY должен иметь вид (id,type,name), а не (type,id,name), как может показаться на первый взгляд. Для тех типов объектов, для которых id не предусмотрен (например, настройки сайта в целом) следует писать в этот столбец какое-то фиксированное значение, например, ноль, и указывать его в явном виде в условии при выборке свойств (т.е. WHERE id=”0″ AND type=”site”). В этом случае PRIMARY KEY будет задействован при любой выборке. В других же ситуациях (например, без условия id=”0″ PRIMARY KEY вида (id,type,name) при выборке объектов с type=”site” задействоваться не будет вообще, а PRIMARY KEY вида (type,id,name) может быть отброшен как неэффективный в том случае, если объектов какого-то типа будет более 30%, что вполне вероятно).

Если требуется обновить или добавить несколько свойств какого-либо объекта в такой таблице (и не известно, были ли такие свойства заданы ранее), имеет смысл производить это следующим образом:
DELETE FROM options WHERE type=”тип” AND id=”ид_объекта” AND name IN (”свойство1″,”свойство2″,…)
INSERT INTO (type,id,name,value) VALUES (”тип”,”ид”,”свойство1″,”значение1″),(”тип”,”ид”,”свойство2″,”значение2″),….
Таким образом, всего двумя запросами можно обновить или добавить любое количество свойств объекта.

Получаем данные из MySql

1. Для одной записи


$q="Select *  from `goods` where id='".$ids[$i]."' limit 1";
$r = mysql_query($q);
$data = mysql_fetch_array($r);

echo $data['row_name'];

mysql_free_result($r);

2. Для нескольких


$q = "select * from `category`";
$result = mysql_query($q);
if (mysql_num_rows($result)==0)

{

echo    'Ничего нет';

}

else{

 while ($row = mysql_fetch_object($result)){

 echo $row->url;
echo '<br>'.$row->name.'</a>';
}
}

Inner Join, Outer (left, right, full) Join в SQL

Ключевое слово join в SQL используется при построении select выражений. Инструкция Join позволяет объединить колонки из нескольких таблиц в одну. Объединение происходит временное и целостность таблиц не нарушается. Существует три типа join-выражений:

  • inner join;
  • outer join;
  • cross join;

В свою очередь, outer join может быть left, right и full (слово outer обычно опускается).
В качестве примера (DBMS Oracle) создадим две простые таблицы и сконструируем для них SQL-выражения с использованием join.
Read more