PDA

View Full Version : php and MySQL самоучител за начинаещи



Lucho
02-06-2009, 17:50
Работа с MySQL - малко теория

MySQL е система за управление на релационна база данни (БД), която използва Structured Query Language (SQL) - най-популярният език за добавяне, прочитане и обработка на информация в базите данни днес. Системата е с отворен код и използването й се подчинява на лиценза GPL. Първата версия на MySQL се появи през януари 1998 година. Може да се използва с голяма група програмни езици - C, C++, Eiffel, Java, Perl, PHP, Python и Tcl и има версии за Linux, UNIX и Windows.
Системата за управление на релационна база данни (RDBMS) позволява създаването, администрирането и работата с релациони бази данни. Тези БД представляват съвкупности от информационни единици, организирани формално в таблици. Достъпът и промяната на данните се извършва без да е необходимо реорганизирането на таблиците или каквото и да било друго в БД. Едно от най-важните предимства на релационните БД е лекотата с която се създават, четат и изтриват записите, както и лесната разширяемост.
Спецовете обясняват, че релационната БД се състои от таблици, в които данните са подредени по колони(категории). Всеки ред съдържа уникално смислено съчетание от данни (стойности на колоните). Така таблицата всъщност свързва категориите, тя е "релация" между тях. Данните от различни таблици също могат да са свързани -- така имаме отново релация, но този път между таблиците. По този начин таблиците и връзките между тях спояват данните в едно логическо цяло, и именно то е (релационна) базата данни.. Ако последните няколко изречения не са ви ясни, няма проблеми. За да не ви се смеят "знаещите", трябва само да запомните, че MySQL не е база данни, а система за управление на база данни. И то не на каква да е БД, а на релационна. Толкова с теорията.
За да стане по-ясен текстът от тук нататък, ще кажем, че базата данни се състои от таблици, всяка от които има колони (указващи каква информация трябва да се съхрани там) и редове (представляващи записите). Всяко парче от данните се поставя в полагащото му се сечение между редовете и колоните - т.е. в съответното поле.

Таблиците

За да покажем как се използва MySQL ще направим една примерна и доста упростена директория от линкове. Нещо като dir.bg, където хората отиват, избират си категория и гледат какви линкове е сложил админът вътре. Нашият вариант на директория ще е доста по-простичък, но нищо не пречи след време да се поупражнявате върху него и да направите супер-съвършенна система за класификация на адреси.

Тук няма да обясняваме как се създава потребител за MySQL сървъра, как се определят правата му, как се създават бази данни и т.н. Приемаме, че сте си намерили хостинг, където администраторът се е погрижил да ви даде потребителско име, парола, база данни, както и информация за адреса и порта на MySQL сървъра (обикновено 6667).
За онагледяване на примерите ще използваме пакета phpMyAdmin (http://www.phpmyadmin.net/), който предоставя Уеб базиран интерфейс към системата. Ще покажем и основните конструкции за изпращане на запитване към БД сървъра.

За да създадем директорията имаме нужда от две таблици - в едната ще съхраняваме категориите, в другата - информацията за сайтовете. Логическата връзка между двете таблици ще се осъществява посредством полета, съдържащи вътрешен идентификатор на категориите, както ще покажем след малко. Като допълнителна възможност - всяка категория ще има възможност да съдържа неопределен брой подкатегории.
Таблицата с категориите ще съдържа три колони - идентификатор на категорията (catid), който ще е число, име на категорията (catname), което ще е низ до 100 знака, без значение дали съдържа букви, цифри и т.н. и идентификатор на родителската категория (catparent).
Основният ключ (primary key) на таблицата ще е полето catid, а имената на категориите няма да могат да се повтарят. Създаваме таблицата така:

CREATE TABLE categories (
catid int(20) NOT NULL auto_increment,
catname varchar(100) NOT NULL,
catparent int(20),
PRIMARY KEY (catid),
UNIQUE CatName (catname)
);

Таблицата със сайтовете ще има общо седем колони - идентификатор на линка (linkid), идентификатор на категорията, в която е класифициран сайта (catid), който е логическата връзка между двете таблици, URL (url) - низ до 255 знака, име на сайта (linkname) - низ до 100 знака, име на добавилия сайта в директорията (izpratil), неговия e-mail адрес (izpratilemail) и дата на добавяне. Основният ключ на таблицата ще е идентификатора на сайта, а за да не стават повторения, URL полето ще трябва да е уникално. Тази таблица създаваме така:

CREATE TABLE links (
linkid int(20) NOT NULL auto_increment,
catid int(20) DEFAULT '0' NOT NULL,
url varchar(255) NOT NULL,
linkname varchar(100) NOT NULL,
izpratil varchar(100) NOT NULL,
izpratilemail varchar(100) NOT NULL,
data int(20) DEFAULT '0' NOT NULL,
PRIMARY KEY (linkid),
UNIQUE Url (url)
);

Създаваме таблиците с SQL инструкцията CREATE TABLE име (дефиниране на таблицата). Синтаксисът може да е доста по-сложен, за подробности погледнете документацията на адрес http://www.mysql.com/doc/en/CREATE_TABLE.html. В скобите указваме структурата на бъдещата таблица, като имаме предвид типа на данните, които искаме да съхраняваме в нея. Отделните иснтрукции се разделят със запетайки, но след последната запетайка не се поставя! Няма значение дали оставяте интервал след запетайката или не.

За създаване на таблици можете да използвате phpMyAdmin, за който вече стана дума, но така или иначе трябва да разберете смисъла на основните типове данни, за да постигнете някакъв резултат. Ако се опитате да създадете таблица, съдържаща полета с неправилно описани изисквания за типа информация, ще получите съобщения за грешка. Ако все пак успеете, то проблемите ще се появят на следващ етап, когато таблицата няма да се държи по начина, по който очаквате.

Базата ни данни вече притежава двете таблици, необходими за директорията :

Създаваме таблиците с SQL инструкцията CREATE TABLE име (дефиниране на таблицата). Синтаксисът може да е доста по-сложен, за подробности погледнете документацията на адрес http://www.mysql.com/doc/en/CREATE_TABLE.html. В скобите указваме структурата на бъдещата таблица, като имаме предвид типа на данните, които искаме да съхраняваме в нея. Отделните иснтрукции се разделят със запетайки, но след последната запетайка не се поставя! Няма значение дали оставяте интервал след запетайката или не.

За създаване на таблици можете да използвате phpMyAdmin, за който вече стана дума, но така или иначе трябва да разберете смисъла на основните типове данни, за да постигнете някакъв резултат. Ако се опитате да създадете таблица, съдържаща полета с неправилно описани изисквания за типа информация, ще получите съобщения за грешка. Ако все пак успеете, то проблемите ще се появят на следващ етап, когато таблицата няма да се държи по начина, по който очаквате.

Базата ни данни вече притежава двете таблици, необходими за директорията :

Типове данни в MySQL

MySQL предлага поддръжка на различни типове данни, но най-вероятно поне на първо време ще са ви необходими четири или пет от тях. Ето описанията на основните, с "х" в скобите е обозначено число, указващо дължината на записа, а квадратни скоби са показани параметри, които не са задължителни.

CHAR (х) - низове с точно определена дължина. Възможната стойност за х е от 1 до 255. Пример :user_id CHAR(10) - очаква се името на модела да е точно 10 символа.

VARCHAR (х) - низове с максимална дължина х. Отново възможните стойности са между 1 и 255. Пример : user_id VARCHAR(10).

INT (х) [Unsigned] - използва се за указване на цели числа между -2147483648 и 2147483647. Ако се използва Unsigned, тогава валидните числа са между 0 и 4294967295. Пример : user_phone INT.

FLOAT [(M,D)] - указва малко дробно число, като М регулира общия брой цифри, от които може да се състои числото, а D ограничава колко от тях може да са зад десетичната запетая.
Ако числото е с повече цифри след запетаята, се прави закръгляне. Пример : suma FLOAT (4,2) - означава, че ако поставите в това поле числа като 2,31 или 22,56, а също и 1, 34 или 1,2, те ще бъдат съхранени правилно. Но ако се опитате да сложите нещо като 32,567, на практика в полето ще се запише 32,57. Ако искате да сте сигурни, че няма да се получи закръгляне, можете да използвате типа DECIMAL.

DATE - използва се за съхранение на дати, както говори и името. Форматът по подразбиране е "ГГГГ-ММ-ДД", като можете да поставяте стойности от '0000-00-00' до '9999-12-31'. MySQL поддържа множество команди за работа с дати, които няма да обсъждаме тук. Пример : born DATE.

TEXT - служи за съхраняване на по-големи низове - от 255 до 65535 символа. При търсене в низовете, съхранявани в такива полета, MySQL няма да прави разлика между малкии големи букви.

BLOB - също като TEXT, с разликата, че търсенето тук взима предвид малките и големи букви.

SET - по-сложна дефиниция, която може би никога няма да използвате, но е добре да знаете. Може да съдържа до 64 предварително дефинирани стойности, от които могат да се избират една или повече. Например : transport SET ("vlak", "avtobus") NOT NULL - от тук имам четири възможности за избор - нито едно от двете, само едното от тях (влак ИЛИ автобус) или и двете (влак И автобус). Както забелязвате, възможните стойности се задават в момента на създаването на таблицата.

ENUM - също като SET, но е позволено избирането само на една стойност. Ако се върнем на горния пример, тук не можем да изберем варианта влак И автобус.


Още за създаването на таблиците

Както забелязахте, когато създавахме двете таблици за директорията - "categories" и "links", дадохме и други инструкции за структурите им, освен типовете данни на отделните полета. Нека погледнем следните инструкциии :

linkid int(20) NOT NULL auto_increment,
PRIMARY KEY (linkid),
UNIQUE Url (url)

NOT NULL означава, че полето не може да остане празно в нито един от записите в таблицата. Попълването му е задължително, в противен случай ще се появи информация за грешка.

AUTO_INCREMENT означава, че стойността на това поле автоматично ще бъде добавена като към стойността на полето от предходния запис се добави 1. Обикновено при този тип полета посочвате NULL като стойност при добавянето на записа. Използва се често за създаване на уникален идентификатор за отделните записи и може да ви свърши много полезна работа.
PRIMARY KEY (първичен ключ на таблицата) е онова поле, което системата използва за да разграничава различните записи. Не може да има два различни реда с една и съюа тойност на полето, определено за първичен ключ. Всяка таблица има свой PRIMARY KEY.
UNIQUE също ще ви гарантира уникалността на информацията. Например в таблицата с линковете искаме да сме сигурни, че в директорията ни няма да има отправки към един и същ сайт два пъти.

Попълване на таблиците

Продължаваме изграждането на примерната директория с добавяне на записите в таблицата за категориите. Съзнателно пропускам подробностите за работа с MySQL от командния ред и в следващите редове ще продължим да използваме phpMyAdmin за да добавяме, редактираме или премахваме записи. Причините за това са две - показаните в шела на Linux таблици от база данни не са най-конфортния начин да разберете какво се случва в базата данни ако тепърва започвате да се занимавате с това. Освен това има доста потребители, ползващи MySQL под Windows, както и такива, чиито хостинг не позволява SSH достъп до сървъра. Затова усложняването е излишно.


Добавяме категориите

Категориите, в които ще разпределяме линковете в нашата директория, ще се съхраняват в таблицата categories, която вече създадохме.
Тя има следните три полета :
- catid - число, съставено от до 20 цифри, което ще представлява уникален идентификатор на категорията. Това число ще бъде добавяно автоматично и ще е с една единица по - голямо от числото в предишния запис.
- catname - низ, който може да е съставен от различни символи с максимална дължина от 100 символа. Тук ще съхраняваме името на категорията.
- catparent - число, съставено от до 20 цифри, което ще указва идентификационния номер (catid) на директорията, която е родителска на текущата.

Ще създадем категория "Музика", в която ще има три под-категории : "Изпълнители", "Групи", "Компании". В подкатегорията "Изпълнители" ще добавим още две подкатегории - "Жени" и "Мъже", а "Групи" ще разделим на "Български" и "Чужди".

В началото ще създадем трите основни категории. За целта ще използваме командата INSERT с чиято помощ ще вкараме три записа в празната все още таблица.

INSERT INTO таблица VALUES ('първа стойност', 'втора стойност', ...);

Този ред ще създаде нов запис в указаната таблица, попълвайки по реда полетата от ляво надясно - в първото поле ще влезе "първа стойност" и така нататък. Стойностите, които искаме да добавим изписваме винаги в единични кавички. Изключение са само числата, които поставяме в поле с типа на данни INT.

Има два алтернативни записа на показания по-горе код:

INSERT INTO таблица (поле1, поле2) VALUES ('стойност1', 'стойност2');

или

INSERT INTO таблица SET поле1=('стойност1'), поле2=('стойност2');

Както се вижда, двата варианта ви позволяват да създадете запис, без да попълвате всички полета в него. Това обаче може да се направи и с първия вариант. Нека демонстрираме на практика тези редове, като ги използваме за да създадем категориите.

INSERT INTO categories VALUES (NULL, 'Музика', 0);

Както можете да видите на долното изображение, вече имаме създадена категория "Музика", която е с идентификационен номер (catid) 1 и родителска категория 0 - тоест, тази категория е от най-високо ниво. Забележете, че използвахме NULL за да укажем, че не искаме да укажем стойност за "catid". Съответно около числото 0, което поставихме в поле, дефинирано като INT, не сложихме единичните кавички.

Сега ще добавим трите подкатегории, като вече в "catparent" ще поставяме числото 1, което е идентификор на категорията "Музика". Ще използваме трите различни начина за употреба на INSERT, създавайки трите подкатегории:

INSERT INTO categories VALUES (NULL, 'Изпълнители', 1);
INSERT INTO categories (catname, catparent) VALUES ('Групи', 1);
INSERT INTO categories SET catname=('Компании'), catparent=(1);

Сега трябва да създадем подкатегориите към "Групи" и "Компании", указвайки за catparent съответно "2" и "4".

INSERT INTO categories VALUES (NULL, 'Жени', 2);
INSERT INTO categories VALUES (NULL, 'Мъже', 2);
INSERT INTO categories VALUES (NULL, 'Блъгарски', 4);
INSERT INTO categories VALUES (NULL, 'Чужди', 4);

Промяна и изтриване на записи

Промяна на запис

Сигурно забелязвате, че при създаването на категорията "български" сме допуснали правописна грешка. За да я поправим, ще се наложи да променим съдържанието на полето "catname" в записа, в който catid има стойност 7. За целта ще използваме командата UPDATE :

UPDATE categories SET catname='Български' WHERE catid='7';

След изпълнението на този ред, грешката ще бъде поправена. Внимавайте с тази конструкция, защото ако пропуснете да посочите условието в WHERE, ще бъде променена стойноста на поелто във всички редове на тази таблица. След малко отново ще се върнем на начините за промяна на вече направени записи.


Изтриване на запис

След като размислим за кратко, можем да решим, че искаме в директорията ни да има само линкове към сайтове за българска музика. Което означава, че ще премахнем категорията за чужди музикални компании. За да направим това ще използваме командата DELETE, за да премахнем този запис в таблицата "categories", където "catid" има стойност 8 :

DELETE FROM categories WHERE catid=8;

Сега ще премахнем и категорията "Български", която вече е излишна :

DELETE FROM categories WHERE catid=7;

Можехме да премахнем двата записа в таблицата само с един ред код, указвайки, че искаме да изтрием редовете, чиито стойности за catid са 7 или (OR) 8 :

DELETE FROM categories WHERE catid=7 OR catid=8 ;



Попълваме директорията

Нека сега добавим по няколко линка във всяка подкатегория на директорията. Сайтовете, които ще използваме в примера са подбрани случайно.

INSERT INTO links VALUES (NULL, 6, 'http://slaviweb.hit.bg', 'Слави Web', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 5, 'http://milena.hit.bg/', 'Милена', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 5, 'http://lili.dir.bg/', 'Лили Иванова', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 6, 'http://valdobrev.hit.bg/', 'Стефан Вълдобрев', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 3, 'http://www.remapool.com/btr/', 'БТР', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 3, 'http://wickeda.hit.bg/', 'Уикеда', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 3, 'http://www.geocities.com/Hollywood/Screen/2009/', 'Нова Генерация', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 3, 'http://bulgarianspace.com/music/artists/pbb/', 'Подуене Блус Бенд', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 4, 'http://www.paynermusic.com/', 'Payner Music.com/', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 4, 'http://www.bol.bg/kamusic/', 'KA Music', 'admin', 'admin@site.com', 0);
INSERT INTO links VALUES (NULL, 4, 'http://bghiphop.hit.bg/producers_sniper.htm', 'Sniper Records', 'admin', 'admin@site.com', 0);

Понеже това е първоначалното "зареждане" на директорията, всички линкове бяха вкарани с подател admin, който притежава e-mail адрес admin@site.com. За дата на този етап поставихме нула, по късно ще покажем какви са вариантите за попълване на това поле.

Изграждане на директорията

PHP дава възможност да постигнете резултата, който искате, по различни начини. За да направят директорията, която сега ще изградим, някои ще напишат кода в поне 10 файла, други ще съберат всичко в един. Някои ще използват функции с които да рисуват отделните части от интерфейса, други ще включат HTML кода направо в PHP блоковете.

Нашият вариант ще се състои от 4 файла - два, които ще представляват общия интерфейс и два,.съдържащи PHP кода. Ще имаме header.php, footer.php, index.php и edit.php. Първите два файла ще се грижат за общия вид на директорията, index.php ще показва линковете, а в edit.php ще добавяме, редактираме или изтриваме линкове.


Общият интерфейс

Когато правите голям сайт е добра идея да използвате един и същ HTML код за оформянето на страниците в него. Най-малкото това ще ви спести пренаписванеот на големи количества код, когато се наложи да промените нещо. Подробно този въпрос разгледахме в 5-а част на самоучителя. Сега ще създадем header.php, който ще съдържа "горната" и "лявата" части от интерфейса, но и ще изпълнява допълнителни функции, като например връзка с базата данни :

<?
//това е header.php

//име на хоста, на който работи mysql сървъра
$bd_host="";
//име на базата данни
$bd="php_test";
//потребителско име
$bd_user="potrebitel";
//парола за това потребителско име
$bd_pass="parola";
//осъществяне на връзката с базата данни
$link=mysql_connect ($bd_host, $bd_user, $bd_pass);
//избираме базата данни,с която ще работим
mysql_select_db ($bd, $link);
//следва интерфейсът
echo "<HTML>\n<HEAD>\n<TITLE>PC World - Увод в PHP - Примерна директория</TITLE>\n<META NAME=\"KEYWORDS\" CONTENT=\"PHP, Web, tutorial, директория\">\n<META NAME=\"DESCRIPTION\" CONTENT=\"Примерна PHP директория\">\n<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=windows-1251\">\n";
echo "<body><img src=\"http://www.idg.bg/public_html/bg/iconpcw-small.gif\" alt=\"PC World - Bulgaria\" align=\"left\" hspace=\"20\">\n<h1 style=\"font:bold 2em sans-serif;color:#3300FF;text-align:center;\">\nУвод в PHP - Директория\n</h1>\n
\n ";
?>


Връзка с базата данни

Преди да направите каквото и да било с базата данни и информацията, съхранявана там, трябва да осъществите връзка с mysql сървъра. За целта трябва да знаете името му, портът на който слуша, трябва да имате потребителско име с някакви права и парола. Информация за тези неща, както и за имената на базите дани, с които можете да оперирате, ще получите от системния си администратор.

Връзката със сървъра става чрез mysql_connect () :

$vryzka=mysql_connect ("име на хост", "потребител", "парола");

Както забелязахте, в примерния файл (header.php) оставихме променливата $bd_host, съдържаща името на хоста празна. В този случай PHP ще се опита да се свърже с mysql сървър, който работи на локалния компютър - localhost. Всъщност освен да оставим променливата празна, можем да й зададем точно такава стойност:

$bd_host="localhost";

В много случаи обаче ще е необходимо да се свързвате с mysql сървър, който не работи на локалната машина. Например

$bd_host="db.idg.bg";

В този случай се предполага, че базите данни се намират на адрес db.idg.bg, а сървърът слуша на порт 3306, който се използва по подразбиране за mysql. Ако на този хост има няколко mysql сървъра или по някаква причина се ползва друг порт (например 3305), връзката би могла да се направи така :

$vryzka=mysql_connect ("име на хост:порт", "потребител", "парола");

Пример:

$vryzka=mysql_connect ("db.idg.bg:3305", "potrebitel", "parola");

Забележете променливата $vryzka, която от този момент нататък става идентификатор на осъществената връзка. Когато искаме да отправим запитване към базата данни, ще използваме точно тази промелива, за да уточним към коя по-точно база данни се обръщаме. Възможно е в един скрипт да осъществим връзки към няколко бази дани, намиращи се на различни mysql сървъри. Тогава идентификаторът е особено важен.

След като вече сме се свързали със сървъра, трябва да уточним с коя база данни искаме да работим:

mysql_select_db ("име на БД", "идентификатор на връзка");

Тук, както и във всички останали функции за работа с mysql, идентификаторът на връката не е задължителен. Ако сте отворили връзка само към един mysql сървър, то всички функции ще използват именно тази връзка.

След като приключим заявките към БД е добре да затворим връзката. Това става чрез функцията mysql_close ("идентификатор"). Нейното използване обаче не е задължително, защото PHP така или иначе ще затвори връзката след като изпълни текущия скрипт.

Ето и footer.php :

<?
mysql_close ($link);
?>
<p align="center" style="font:bold .7em sans-serif;color:#000000">
Самоучител по PHP - Тестова директория


Поредица на PC World - Bulgaria (http://www.pcworld.bg)

<? echo date ("d.m.Y, H:i:s"); ?>
</p>
</body>
</html>



Постоянните връзки

Има и още един начин за осъществяване на връзка с базата данни:

$vryzka=mysql_pconnect ("име на хост", "потребител", "парола");

Така отваряме постоянна (persistent) връзка със mysql сървъра, която няма да бъде затворена нито в края на изпълнението на скрипта, нито чрез функцията mysql_close (). Веднъж изградена, връзката си остава отворена за последващи употреби.
Този вариант е добър при наистина натоварени и сложни сайтове, изискващи множество заявки към базата. Но ако използвате споделен mysql сървър, на който разчитат още потребители, постоянните връзки са сигурен източник на проблеми. Освен това в някои версии на PHP резултатите могат да се окажат непредвидими.
С няколко думи - не използвайте mysql_pconnect освен ако не сте 100% убедени, че ви е необходимо, ако системният администратор ви е разрешил и ако сте тествали изцяло как ще се представи сайтът ви.

Търсене в таблиците

Да прегледаме категориите

Сега можем да пристъпим към създаването на индексният файл, който ще показва линковете в директорията. Той има две основни задачи - да провери за налични категории и подкатегории, както и за съответните им линкове.

Заявките се изпращат към базата данни чрез функцията mysql_query () :

$result=mysql_query ("заявка", "идентификатор");

И тук указването на идентификаотр на връзка не е необходимо, ако използваме една база данни. Отговорът от заявката ще бъде записан в променливата $result за по-нататъчна употреба. Ако по някаква причина възникне грешка, функцията ще върне FALSE.
Ето как ще направим заявка за да проверим кои са категориите от най-високо ниво в нашата директория:

$top_cat=mysql_query ("SELECT * FROM categories WHERE catparent=0");

Резултатът, който заявката връща е доста по-абстрактен отколкото можете да си представите, така че не можем просто да го изпишем на екрана. най-просто казано той ще представлява масив, съставен от други масиви. За да разберем какво точно ни е върнала базата ще се наложи да обходим резултата. Тъй като знаем, че в таблицата има три полета, ще предвидим три променливи, които да съхраняват стойностите. Сега пред нас остават три възможности. Първата- да получим всеки ред от таблицата в БД във вид на числово номериран масив. Втората възможност е подобна, но ключовете в масива ще отговарят на имената на полетта в таблицата. Третата е да получим резултатат в обектен вид.
За да получим редовете във вид на числово индексиран масив, използваме функцията mysql_fetch_row(). Тя ще обходи текущия ред от резултата и ще върне масив с ключове от 0 нагоре. При всяко поредно извикване на функцията, тя ще се премества сама на следващия ред в резултата, а когато достигне края ще върне FALSE. Това означва, че можем да я използваме в while цикъл, както показвахме това в 8-ма част на самоучителя :

while ($cat_row=mysql_fetch_row ($top_cat)) {
echo "Категорията $cat_row[1] е с ID $cat_row[0] и родителска категория с ID - $cat_row[2]";
}

Накратко - заявката, която изпратихме върна само един резултат, защото само една е категорията от най-високо ниво, която дефинирахме.
Чрез mysql_fetch_row получихме всички данни от този ред в масив, като първото поле (ID на категорията) влезе в елемент с ключ 0, второто поле (името на категорията) влезе в елемент с ключ 1, а третото поле - с ID на родителската категория, откриваме в елемент с ключ 2.

Същият резултат бихме могли да постигнем и чрез функцията mysql_fetch_array(), но тук вече няма да се сблъскваме с номерация :

while ($cat_row=mysql_fetch_array ($top_cat)) {
echo "Категорията $cat_row[catname] е с ID $cat_row[catid] и родителска категория с ID - $cat_row[catparent]
";
}

Резултатът ще бъде същия. Нека сега за да демонстрираме цикъла премахнем ограничението за категория и да ги покажем всичките:

$top_cat=mysql_query ("SELECT * FROM categories WHERE catparent=0");
while ($cat_row=mysql_fetch_array ($top_cat)) {
echo "Категорията $cat_row[catname] е с ID $cat_row[catid] и родителска категория с ID - $cat_row[catparent]
";
}


Стана дума за обектното представяне на резултата. Същият листинг на категориите ще получим и ако използваме следния код :

$top_cat=mysql_query ("SELECT * FROM categories");
while ($cat_row=mysql_fetch_object ($top_cat)) {
echo "Категорията $cat_row->catname е с ID $cat_row->catid и родителска категория с ID - $cat_row->catparent
";
}

Тук използвахме функцията mysql_fetch_object() за да получим реда от резултата във вид на обект.

Важно : PHP предоставя механизми и за обектно програмиране, които, макар и да не са сред май-силните му страни, в някои случаи могат да са полезни за решаване на по-трудни задачи. Тъй като в този самоучител не се занимаваме с този аспект на PHP, няма да разглеждаме и възможностите за обектна обработка на резултатите от SQL заявките. Другите два варианта са много по-често използване и са напълно достатъчни за да задоволят всички изисквания.

Съществуа и още един начин за съставяне на конструкцията с която обхождаме резултата. Знаем, че в отговор на заявката ще получим данните от три полета - ID, име и родителска категория. Затова можем да определим свои променливи, които да съхраняват тези резултати:

while (list ($id, $name, $parent)=mysql_fetch_array ($top_cat)) {
echo "Категорията $name е с ID $id и родителска категория с ID - $parent
";
}

Извеждане на категориите и линковете

Сега вече можем да напишем кода на index.php, който ще показва категориите и линковете, съхранявани в тях.
В променливата $p съхраняваме идентификационния номер на текущата директория, за да намерим линковете и поддиректориите, принадлежащи към нея.

<?
include "header.php";

//извеждане на категориите
echo "
<h2>Категории: </h2>";
//ако не съществува променлива $p, търсим подкатегориите на основната
if (!$p) {
$cat=mysql_query ("SELECT * FROM categories WHERE catparent=0");
}
else {
//намираме името на текущата категория
$tazi_categoria=mysql_fetch_array(mysql_query ("SELECT catname FROM categories WHERE catid='$p'"));
echo "Текуща категория : $tazi_categoria[catname]
";
//намираме подкатегориите на текущата категория
$cat=mysql_query ("SELECT catid, catname FROM categories WHERE catparent='$p'");
}
while (list ($id, $name)=mysql_fetch_array ($cat)) {
echo " <a href=index.php?p=$id>$name</a>
";
}

//извеждане на линковете
echo "

<h2>Линкове: </h2>";
if (!$p) {
$site=mysql_query ("SELECT linkid, url, linkname FROM links WHERE catid=0");
}
else {
$site=mysql_query ("SELECT linkid, url, linkname FROM links WHERE catid='$p'");
}
//ако няма намерени резултати, изписваме съответното съобщение
if (!@mysql_num_rows($site)) {
echo "Няма линкове в тази категория!
<a href=\"edit.php?p=$p\">Кликнете тук за да добавите сайт!</a>";
}
//в противен случай извеждаме линковете
else {
while (list ($lid, $lurl, $lname)=mysql_fetch_array ($site)) {
echo " редактирай ($lurl>$lname</a>))
";
}
echo "

<a href=\"edit.php?p=$p\">Кликнете тук за да предложите сайт!</a>";
}
include "footer.php"
?>


Управление на линковете

Сега е време да създадем и четвъртия файл за примерната директория, където ще става добавянето, промяната и изтриването на линковете. Той ще показва и формите, в които потребителите ще въвеждат съответната информация.
Ако разгледате внимателно кода на index.php ще видите, че този файл може да бъде извикан с посочени стойности за променливите $p или $e. В зависимост от това коя променлива притежава стойност,. ще бъдат предприемани и съответните действия.
Например ако променливата $p има стойност, а $e е празна, очевидно искаме да добавяме нов линк в директорията, чието ID се съдържа в $p. Ако само $e съдържа стойност, то явно ще редактираме линкът, чието ID е в нея. Ако и двете променливи са празни, ще добавяме сайт към основната категория.
В случаите, когато ще се добавя или редактира линк, ще е необходимо да се изведе и съответната форма. След извършване на съответното действие ще покажем потвърждение или съобщение за грешка с връзка към индекса на директорията.
Вътре в самия файл обаче ще въведем и още няколко роменливи - $ins ще съдържа категорията на евентуалния нов линк, $del ще съдържа ID-то на линк, който евентуално искаме да изтрием, $do_edit на линк, който евентуално ще променяме. Ето и кода :

<?
include "header.php";

//функция, която ще използваме за да проверяваме валидността на информацията във формата
function check_form () {
global $link, $linkname, $linkurl, $linkcat, $izpratil, $izpratil_email;
//дали посоченият адрес е валиден?
if (!eregi("^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\.-][a-z0-9]+))*$",$izpratil_email) ) {
echo "Посочили сте невалиден e-mail адрес! Моля, върнете се и поправете грешката!";
include "footer.php";
exit;
}
//дали всички полета са попълнени?
if ((!$linkname) || (!$linkurl) || (!$linkcat) || (!$izpratil) || (!$izpratil_email)) {
echo "Не сте попълнили всички задължителни полета! Моля, върнете се и поправете грешката!";
include "footer.php";
exit;
}
}

//проверка за променлива $del за да изтрием линка
//идентификационният номер на линка ще намерим в променливата $linkid
if ($del) {
if (!mysql_query ("DELETE FROM links WHERE linkid='$linkid'")) {
echo "<font color=\"#FF0099\">Линкът не може да бъде премахнат в момента!</font>";
include "footer.php";
exit;
}
else {
echo "Линкът бе премахнат!

<a href=\"index.php\">Обратно към директорията.</a>";
include "footer.php";
exit;
}
}

//проверка за промелива $ins
if ($ins) {
//проверка за валидността на формата
check_form ();
//определяне на датата
$data=date ("Y-m-d");
//добавяне на сайта
if (!mysql_query ("INSERT INTO links VALUES (NULL, '$linkcat', '$linkurl', '$linkname', '$izpratil', '$izpratil_email', '$data')")) {
echo "<font color=\"#FF0099\">Линкът не може да бъде добавен в момента!</font>";
include "footer.php";
exit;
}
else {
echo "Линкът бе добавен!

<a href=\"index.php\">Обратно към директорията.</a>";
include "footer.php";
exit;
}
}

//проверка за променлива $do_edit
if ($do_edit) {
//проверка за валидността на формата
check_form ();
$data=date ("Y-m-d");
//редактиране на сайта
if (!mysql_query ("UPDATE links SET catid='$linkcat', url='$linkurl', linkname='$linkname', izpratil='$izpratil', izpratilemail='$izpratil_email', data='$data' WHERE linkid='$linkid'")) {
echo "<font color=\"#FF0099\">Линкът не може да бъде редактиран в момента!</font>";
include "footer.php";
exit;
}
else {
echo "Линкът бе редактиран!

<a href=\"index.php\">Обратно към директорията.</a>";
include "footer.php";
exit;
}

}

//проверка за променлива $e - ако ще рeдактираме линк, трябва да изведем текущата информация за него
if ($e) {
//дали има линк с това ID или някой се шегува?
$link_info=mysql_query("SELECT * FROM links WHERE linkid='$e'");
if (!mysql_num_rows($link_info)) {
echo "Няма такъв сайт в директорията

<a href=\"index.php\">Моля, проверете отново!</a>";
include "footer.php";
exit;
}
//ако ID-то е коректно, изтегляме информацията за сайта
//всички данни ще се съхраняват в масива $link_arr, като ключове за отделните му елементи са имената на полетата
$link_arr=mysql_fetch_array($link_info);
}

//извеждаме формата за въвеждане на информация
//ако в масива $link_arr има дани, те ще се изпишат
?>
Въведете желаната информация :


<form method="post" action="edit.php">
Име на сайта :
<input type="text" name="linkname" value="<? echo $link_arr[linkname]; ?>">


Адрес :
<input type="text" name="linkurl" value="<? echo $link_arr[url]; ?>">


Категория :
<select name="linkcat">
<?
//създаваме падащо меню, съдържащо списък на категориите
$cat_list=mysql_query("SELECT catid, catname FROM categories");
while (list($catid, $catname)=mysql_fetch_row($cat_list)) {
//ако категорията е тази, която ни е необходима, определяме тази опция като избрана
if (($catid==$p) || ($catid==$link_arr[catid])) {
echo "<option value=$catid SELECTED>$catname</option>";
} else {
echo "<option value=$catid>$catname</option>";
}
}
?>
</select>


Вашето име :
<input type="text" name="izpratil" value="<? echo $link_arr[izpratil]; ?>">


Вашият e-mail адрес :
<input type="text" name="izpratil_email" value="<? echo $link_arr[izpratilemail]; ?>">


<input type="submit" value="Изпрати информацията!"> <input type="checkbox" name="del"> Изтрий записа!
<?
//поставяме "флаг" за добавяне или изтриване
if ($e) {
echo "<input type=hidden name=linkid value=$e>";
echo "<input type=hidden name=do_edit value=1>";
}
else {
echo "<input type=hidden name=ins value=1>";
}
?>
</form>
<?
include "footer.php";
?>

Този код може да ви се види сложен в началото, но той демонстрира възможностите, които PHP ви дава да изберете как да структурирате приложението си. Някои биха поставили съдържанието на edit.php в поне 4 файла, други пък биха събрали цялата директория в един (поставяйки header и footer съдържанието във функции, а целия edit.php в if конструкции).
Демонстрационната директория не е особено красива и функционална, но това е основа, върху която могат да се добавят нови и нови елементи.

Благодарение на: CARPEX;COBRA;GoGleto;Sixkiller(аз);InLoV4yY и digitAL; bg-best 2009 (c)