PHPClub Cookbook - Русский PHP FAQ

PHPClub, faq@phpclub.net

Version 1.1 / 2001-12-06 19:12:51


ЗАДАВАЙТЕ ЛЮБЫЕ ВОПРОСЫ СОГЛАСНО ТЕМЕ!
Все авторские права принадлежат "Клубу разработчиков PHP" (PHPCLub) и Dmitry Borodin http://php.spb.ru а также всем авторам участвующим в разработке материалов этого документа. Любое использование этих материалов в коммерческих целях не допустимо без согласования. При копировании оставляйте пожалуйста ссылки на нас. :)
http://www.phpclub.net
http://php.spb.ru
Все вопросы пишите на faq@phpclub.net

1. Первая задача по созданию FAQ

2. Текущие вопросы - кто ответчает, перенесите вопрос в соотв. раздел и там отвечайте.. Спасибо

3. О создателях этого FAQ

4. Что такое PHP

5. Где взять

6. В чем лучше создавать скрипты?

7. Установка и настройка (PHP,ZEND,MODULES,MYSQL,POSTGRES)

8. Динамическое создание сайта (принципы и технологии)

9. Типы данных

10. Переменные языка

11. Операторы

12. Выражения (+ошибки)

13. HTML Формы

14. HTTP Cookies

15. Функции(область видимости, где применять)

16. Массивы (работа, практика, PHP4)

17. Обьекты (работа, this, хранение)

18. Строки (функции, использование, кеширование для вывода)

19. Работа с файлами,DBF,CVS

20. Работа с shared memory (чат)

21. Работа с БД (враперы, тонкости, грамотное проектирование)

22. Работа с COM-обьектами

23. Сравнение баз MySQL & Postgres & MSSQL

24. Графика (работа, GIF,PNG, шрифты, Flash)

25. Сеть (соскеты, whois, pop3, unr_encode)

26. Почта (кодировки, вложения, IMAP, TWIG)

27. Куки, хеадеры, сессии (авторизация, переменные окружения, эмуляция сессий)

28. Безопасность (сервера, скриптов, SSL)

29. Шаблоны. (Easy,FastTemplate)

30. E-Shop (принцип построения, работа)

31. DB: MySQL

32. DB: Postgres

33. DB: Oracle

34. DB: MSSQL

35. DB: Interbase

36. DB: Sybase

37. XML & XSLT

38. DEMO ZONE !!!

39. Буферизация вывода (GZIP & ...)

40. Отлов ошибок

41. Пасхальные яйца в PHP


1. Первая задача по созданию FAQ

Section Content

1.1 Что добавлять сюда?

Во первых надоевшие вопросы из форумов!
Только осторожнее. Создавайте корректные - понятные названия...

1.2 У меня нет доступа для написания,редактирования..


Здесь гибкая система прав. Напишите faq@phpclub.net свои данные.

1.3 Чем я могу помочь вашим начинаниям?

Любая помощь приветствуется...
Вспоминайте свои бывшие ошибки, проблемы
Напишите вопрос и варианты его решения..

1.4 Как я могу делать линки в FAQ?

С помощью тега <LINK> сам текст | сам линк и закрывающий тег линк

Имя линка

1.5 Как ВЫ думаете вопросы должны приходить по мылу? И запишите свои приоритеры в ведении разделов... в раздел о создателях


2. Текущие вопросы - кто ответчает, перенесите вопрос в соотв. раздел и там отвечайте.. Спасибо

Section Content

2.1 Существует ли в PHP наряду с константой "feof", константа "FEOL" для чтения до конца строки (End of Line).

2.2 Как с помощью PHP организовать хранение паролей в файлах паролей Линукса (passwd...).

http://phpclasses.upperdesign.com/browse.html/package/222

Тут находится класс, для работы с /etc/passwd но я думаю, что переделать его под свои нужды не составит никакого труда

2.3 Как текстовую информацию больших размеров, или даже картинки с помощью PHP запихать в PostgreSql.


3. О создателях этого FAQ

Section Content

3.1 Кто администрит это все?

Администрированием занимаются сами посетители данного ресурса. Для того чтобы получить логин и пароль, достаточно быть полностью уверенным в своих силах и написать письмо на phpclub@unet.ru с заголовком - "Хочу участвовать в создании faq.phpclub.net".
В письме укажите следующее:
Логин
Пароль
E-mail
Ф.И.О.

ну и чтобы сомнений в квалификации не было, парочку ссылок на свои работы.


4. Что такое PHP

Section Content

4.1 Что такое PHP?

PHP это скриптовый server-side язык программирования, предназначенный в основном для включения в html страницу и выполняемый сервером перед выдачей страницы браузеру. Это не CGI, но вполне заменяет его! PHP очень похож на ASP (существует даже конвертор asp2php), но приспособлен к unix-like системам и чаще всего употребляется с web-сервером apache, хотя может работать и с MS IIS и в принципе с любым другим веб-сервером. Кроме того, PHP3 является объектно-ориентированным.

На мой взгляд, основное преимущество PHP - простота, гибкость и скорость выполнения. Мне, например, понадобилось минут 15 для просмотра мануалов и примеров, для того, чтобы перевести весь контент моего сайта на SQL (подробнее с елудющих ШАГ-ах) и написать php-скрипт для выдачи его в html коде с шаблонным дизайном. Зачем так сложно? А вовсе и не сложно. Теперь, чтобы выложить на сайт новую статью или просто новость, я всеголишь добавляю новую запись на sql сервере с помощью MS Access или web-интерфейса sql, написанного кстати тоже на php, а при запросе страницы пользователем соответствующий php-скрипт выуживает из sql то, что ему надо и выдает уже красиво оформленную, готовую страницу.

SQL. Вот это является еще одним преимуществом PHP, такое впечатление, что он (PHP) просто рожден существовать в связке apache+php+sql. Для свой работы я выбрал MySQL, который также существует и под linux и под win9x/NT.

В качестве иллюстрации простоты php, предлагаю пример, передающий список файлов в текущем каталоге.

<HTML><BODY>
Список файлов:
<?
$dir = opendir(".");
while($file = readdir($dir))
echo "$file<BR>";
closedir($dir);
?>
</BODY></HTML>

Код, помещенный в теги <? и ?> не передается браузеру, а выполняется непосредственно на стороне сервера. А выдается то, что выводит команда echo. Я думаю, что человек, мало-мальски знающий хотя бы один язык программирования, поймет этот пример без проблем. Кажется, PHP похож на C? или Perl? или Basic? А вот к стати тот же пример в ООП варианте:

<?
$dir = dir(".");
while($file = $dir->read())
echo "$file<BR>";
$dir->close();
?>
И ведь вы можете это писать в своем любимом html редакторе! Лично я настолько полюбил этот язык, что пишу в нем и скрипты для linux shell (хотя это уже из области XXX ;) и даже под dos/win. А запустить скрипт из шела проще некуда: php3 -q <filename> получается отличный интерпретатор.

А вот, для наглядности, еще пример для работы с MySQL:

<?
$conn=mysql_connect("127.0.0.1");
if (mysql_select_db("db",$conn)) {
$res=mysql_query("select * from tabl", $conn);
while(($data=mysql_fetch_row($res)))
echo("$data[0] $data[1]\n");
} else
echo "Error!\n";
?>
Этот скрипт выводит таблицу tabl из базы данных db на локальном MySQL сервере.


5. Где взять

Section Content

5.1 Основные сервера

PHP.NET - основной сервер разработчиков.
ZEND.COM - сервер команды движка ZEND (кодеры скриптов, кеш)


6. В чем лучше создавать скрипты?

Section Content

6.1 EditPlus 2

На мой взгляд, это самый оптимальный редактор для создания/отладки скриптов. Причём не важно каких скриптов, поскольку в этом редакторе можно настроить, кажется, абсолютно всё. Очень удобная подсветка текста (Highlighting) с поддержкой синтаксиса, просто великолепная система проектов, пользовательские шаблоны, автозавершение (тоже полностью регулируемое), закачка по FTP, поиск/замена во всех открытых файлах, огромный архив пользовательских файлов, с синтаксисом для-всего-на-свете и другими полезностями...
Минуса только три - неудобная подсветка CSS по умолчанию, невозможно выделять блоки, только линии (но редактора с блоковым выделением вообще кажется нет :) и то что EditPlus - shareware на 30 дней. Впрочем код в сети находится ~за 15 минут.
P.S. Чуть не забыл - живёт тут

Comments from dRam:
Полностью согласен с автором, за исключением одного ...
В EditPlus есть возможность выделения блоков. Для этого выключаем word-wrap (Ctrl+Shift+W), нажимаем Alt+C, выделяем блок текста (в произвольном месте), Ctrl+C, выбираем куда вставить Ctrl+V ... :)

6.2 PHP Coder & DBG, как подружить

6.3 UltraEdit32

UltraEdit32 http://www.ultraedit.com|http://www.ultraedit.com</LINK>. Прекрасный редактор для
программиста. Обладает множеством необходимых функций в т.ч.:
практически любая синтаксическая подсветка (файлы можно скачать на
сервере)
работа по ftp
поддержка проектов
работа в режиме колонок/блоков
hex-редактирование
полностью настриваемая панель инструментов, usertools, подсветка
макросы
и многое другое...
единственный недостаток - вставка html-тагов, по моему мнению,
организована не очень удачно.


7. Установка и настройка (PHP,ZEND,MODULES,MYSQL,POSTGRES)

Section Content

7.1 Как установить?

Во первых строках своего письма хочу сообщить, что хотя инсталяция PHP - дело совсем не хитрое и по крайней мере линуксоиды, отличающиеся умом и сообразительностью ;-) , а так же уменем вникать в тексты документации на любом языке, с этим делом справляются на р-р-р-р-аз, у виндозистов зачастую возникают странные, на мой взгляд, вопросы. В таком случае целесообразно всетаки рассмотреть инсталяцию PHP, но только под windos. Сразу предупрежу, что способов работы с php существует несколько и я не буду здесь описывать каждый из них, а лишь один и самый простой, на мой взгляд. Также учтите и то, что этот способ не является безопасным (всмысле вашего сервера, читайте security.shtml в мануале от PHP), да и о какой безопасности под виндами может идти речь. Хотя линчо у меня на моей WindowsNT стоят Apache, MySQL и PHP - они естественно используются лишь для отладки скриптов, перед выкладыванием их на сервер и эта комбинация не является полноценным вебсервером, поэтому к неу нет доступа извне. Зато очень даже здорово отлаживать скрипты и дизайн, таким образом, всем рекомендую.

Начнем с того, что вам не стоит скачивать и компилировать PHP из исходного кода, это лишнее. Возьмите готовый дистрибутив (у меня он назывался php-3.0.11-win32.zip) и просто скопируйте все файлы туда, где вы хотите содержать php (лично у меня это c:/php3/). Пол дела сделанно! Кстати, кроме самого дестрибутива, вам понадобится еще и документация, валяющаяся на том же сервере ( список, html-вариант).

Идем дальше. Теперь в первую очередь вам необходимо отредактировать файл php3.ini (оригинал php3.ini-dist). Измените в нем праметр extension_dir=<путь где лежит ваш PHP3 со всеми модулями> (у меня, как говорилось это c:/ php3/), а также уберите коментарии со строк extension= с теми модулями, которые вам будут необходимы (если вы не просекаете и смысл, значит вам они не нужны). И все! Теперь поместите этот файл (php3.ini) в корневой каталог вашей windows (c:\windows обычно). Собственно сам php3 - готов. Что-бы проверить его работу - создайте файл со следующим содержимым:

<?
echo "Список файлов\n";
$dir = dir(".");
while($file = $dir->read())
echo "$file\n";
$dir->close();
?>
и запустите его так <путь к вашему php>/php.exe -q <имя файла>. Для особо талантливых обьясняю подробнее. Если вы поместили все файлы из дистрибутива php в каталог c:/php3/, а созданный вами файл с вышеописанным скриптом называется test.php то запустить его вам нужно будет так:

c:/php3/php.exe -q test.php
Этот скрипт должен вывести список файлов в текущем каталоге.

Следующий шаг - конфигурирование вебсервера для работы с PHP. Если вы используете IIS - ваши проблемы ;) (используйте файл php_iis_reg.inf в поставке PHP3), если вы используете apache, то сейчас я вам помогу.

Вообще идеология обработки php-сценариев сервером очень проста. Есть такое понятие как mime тип файла, который определяется по расширению, гляньте в файл mime.types и вы сами, надеюсь, все поймете. Файл имеет простой формат: <тип файла> <расширение файла>. Вот мы и вставим в него следующие три строчки:

application/x-httpd-php3 php
application/x-httpd-php3 php3
application/x-httpd-php3 phtml
Что мы этим имеем ввиду? Что файлы с расширением php, php3 и phtml являются приложением (application) типа x-httpd-php3 (а можете и сами название этого типа придумать, дальше поймете зачем это вообще нужно). Есть, к стати, и второй вариант прописывания mime типов, напрямую в httpd.conf вот так:

AddType application/x-httpd-php3 .php
AddType application/x-httpd-php3 .php3
AddType application/x-httpd-php3 .phtml

После того. Как мы покончили с определнием типов (и все знают этих типов). Нам осталось добавить в httpd.conf всего одну строчку для запуска этих сценариев. Вот эту: Action application/x-httpd-php3 <путь и имя php транслятора> Которая означает, что для файлов типа application/x-httpd-php3 запускать указанную вами прогу. у меня под win эта строчка выглядит так:

Action application/x-httpd-php3 /cgi-bin/php.exe
То есть я положил сам php.exe в директорию прописанную как /cgi-bin/ и не мучался (добавить три лишние строки) с прописыванием разрешения на запуск из собствненой директории php.

Собственно вот и все. Запускайте ваш вебсервер и пробуйте скрипты из архива с документацией от php или описанные мной. Если у вас все таки что-то неработает - смотрите логи от вебсервера.

Опишу в кратце еще раз все необходимые действия:
скопировать php дистрибутив в выранную вами директорию;
соответсвенное конфигурирование php3.ini (добвление этой самой директории) и помещение его в директорию windows;
добавление новых mime типов для распознавания документов, содержащих сценарии php;
сообщение серверу что делать с документами этих типов (запускать для них php.exe)

7.2 MySQL под Sun SparcSolaris 7

Эти строки не претендуют на правильность но у меня всё получилось именно таким методом.

При установке я столкнулся с неожиданными трудностями. Первая состояла в том, что MySQL напрочь отказывался конфигурится с параметрами или без таковых говоря при этом что checking size of char..0 и то, что наверно у меня отсутсвует libm.a . Я проверил все пути (библиотека оказалась в /usr/lib так что всё должно было быть ок!), проверил наличие zlib, gtar (с обычным сановским tar скорее всего будет проблема), сменил cc на gcc-2.95.3. Проблема всё равно осталась. После чего заглянув в config.log я нашёл место где сваливалось configure. Вот оно : configure:6540: unterminated `#if' conditional
configure: failed program was:
line 6535 "configure"
#include "confdefs.h"
#include <stdio.h>
main()
{
FILE *f=fopen("conftestval", "w");
if (!f) exit(1);
fprintf(f, "%d\n", sizeof(char));
exit(0);
}.
Cудя по всему это баг в mySQL но его можно обойти (вероятно это не совсем правильно но тем не менее после этого я смог запустить СУБД. Просто создаёте файл conftestval после чего записать туда 1.

Далее
После запуска gmake all при линковке libtool солярка просто свалилась в core. Использование стандартного Sun'вского make решило все траблы.

7.3 Как PHP установить Pentium100 с очень маленьким винтом под WIN95?

Начнем с того, что я и сейчас не знаю, имеет ли данная конфигурация
практическую ценность. Очень может быть, что моя проблема являлась частной.
Короче - мне надо было установить PHP на Пентиум 100 с Windows 95 и малым
размером жесткого диска - ок. 500 МБайт. Пользователь такого компьютера
просто вынужден экономить каждый мегабайт. Кроме того, компьютер не был
подключен к Интернету либо к локальной сети, поэтому весь софт для него
приходилось грузить на флоппи.
Известный мне легкий вариант - установка сервера ОМНИ - не сработал. Новый
ОМНИ создан уже для Windows 98/МЕ/2000. Совершенствовать Windows 95 у меня
явно не хватало квалификации. Инсталляционник Apache великоват, вдобавок,
судя по описапниям, тоже имеются проблемы с Windows 95.
В одном из немецких форумов мне попалась ссылка на сервер BadBlue -
www.badblue.com. Сервер оказался вполне компактным (инсталляционник ок. 600
кБайт) и предельно легким в установке. Собственно говоря, существуют две
версии сервера - для Windows 95 и для более высоких версий. Для
установки РНР следовало:
- установить РНР в выбранную директорию;
- скопировать файл php.ini-dist в директорию Windows и переименовать в
php.ini ;
- при отключенном сервере отредактировать файл EXT.INI (обычно находящийся
в c:\program files\badblue\pe) путем добавления строчек:
[SERVICES]
extension1=php,c:\php\php.exe
(конечно, путь к РНР должен быть указан правильно).
Недостаток, на мой взгляд, заключается в расположении файла конфигурации
EXT.INI в одной директории с собственно программными файлами РНР
(http://127.0.0.1/ - c:\program files\badblue\pe). В эту директорию для
проверки пишите тестовый файл .
В настоящее время у меня в данной конфигурации стоит РНР3. Попытка
"привязать" РНР4 из комплекта ОМНИ провалилась. Однако, поскольку цель
установки - дать возможность 13-летнему школьнику освоить в первом
приближении синтаксис языка и писать простые программы - достигнута, дальше
эксперименты пока не проводились.
Ниже я скопировала информацию с сайта www.badblue.com. Я не претендую на
хорошее знание предмета, и вполне может быть, что в оригинальной информации
Вы найдете нечто более ценное, чем я могу не то что истолковать, а и
представить.
С уважением,
Елена Геллер
How do I get started with PHP?

If you don't already have it, download <down.htm> BadBlue. Download
<http://www.php.net/downloads.php> one of the PHP Win32 Binaries (either
the installer or the ZIP file). When installing or unzipping the Win32
Binary version of PHP, note the folder to which PHP is installed. Remember
to copy a PHP INI file (e.g., php.ini-dist) to the Windows directory and
rename it php.ini. Stop the BadBlue service. Edit the BadBlue EXT.INI file
(usually in the directory c:\program files\badblue\pe) by adding the lines:
[SERVICES]
extension1=php,c:\php\php.exe
making sure that the path to PHP.EXE is correct.
Start the BadBlue service. Test BadBlue's PHP support by saving a test page
(see below for a sample) in the directory where BadBlue is stored (e.g., as
c:\program files\badblue\pe\hello.php). Type the name of your site with the
file name (e.g., <http://127.0.0.1/hello.php>).
Which built-in (CGI) variables does BadBlue support?

Built-in Variable Description
ALL_HTTP All raw headers in HTTP format
ALL_RAW All raw headers (IIS *)
CONTENT_LENGTH Header: Content-length
CONTENT_TYPE Header: Content-type
DOCUMENT_ROOT Server path to HTML document root
GATEWAY_INTERFACE Current CGI version
HTTP_ACCEPT Header: Accept
HTTP_ACCEPT_ENCODING Header: Accept-encoding
HTTP_ACCEPT_LANGUAGE Header: Accept-language
HTTP_COOKIE Header: Accept-cookie
HTTP_HOST Header: Host
HTTP_REFERER Header: Referer
HTTP_USER_AGENT Header: User-agent (browser)
PATH_INFO Requested URL
PATH_TRANSLATED Script filename (if any)
QUERY_STRING Form GET query string
REMOTE_ADDR Remote IP address
REMOTE_USER Basic authentication user name
REMOTE_PASSWORD Basic authentication password
REQUEST_METHOD HTTP request method
REQUEST_URI Complete URL of requested page
PHP_AUTH_USER Basic authentication user name (Apache *)
PHP_AUTH_PW Basic authentication password (Apache *)
REQUEST_METHOD Header: request method
REQUEST_URI Requested URL
SCRIPT_FILENAME Script filename (if any)
SCRIPT_NAME Script filename (if any)
SCRIPT_URI Complete URL of requested page
SCRIPT_URL Requested URL
SERVER_PORT Server listen port
SERVER_PROTOCOL Server name and protocol
SERVER_SOFTWARE Server name and version
* Certain variables are supported for compatibility with other servers
ТерминСписокопределенийАдресаЦитатыГотовыйDownload
<http://www.mysql.net/downloads/index.html> and install MySQL (Gamma). Open
a command window and start MySQL.
cd \mysql\bin
mysqld
Create a database using the root account.
mysqladmin -u root create mydb
Create the following SQL which must be on separate lines, making sure they
lines don't wrap, and save it to the MySQL bin directory, e.g.,
c:\mysql\bin\test.sql .
CREATE TABLE users (id tinyint(4) DEFAULT '0' NOT NULL AUTO_INCREMENT,
first varchar(20), last varchar(20), address varchar(255), company
varchar(50), PRIMARY KEY (id), UNIQUE id (id));
INSERT INTO users VALUES (1, 'Arnold','Fizbin','25 Wide St.','TinyCo');
INSERT INTO users VALUES (2, 'Fred', 'Fernakadan', '50 My Way', 'BigCo');
INSERT INTO users VALUES (3, 'Doris','Spam', '15 Top Rd', 'Zindi Corp');
If the lines wrap, make sure that each statement is on a new line.
Execute the create and inserts:
mysql -u root mydb <test.sql
Save the following page to c:\program files\badblue\pe\mysql.php.
<html><body>
<?php
$db = mysql_connect("localhost", "root");
mysql_select_db("mydb", $db);
$result = mysql_query("SELECT * FROM users", $db);
printf("First Name: %s<br>\n", mysql_result($result, 0, "first"));
printf("Last Name: %s<br>\n", mysql_result($result, 0, "last"));
printf("Address: %s<br>\n", mysql_result($result, 0, "address"));
printf("Company: %s<br>\n", mysql_result($result, 0, "company"));
?>
</body></html>
Run the page in the browser to display the first record.
http://127.0.0.1/mysql.php

7.4 Установка PHP 4.0.x в виде ISAPI-фильтра под IIS 5.0

Проверено на:
- Win2000 Pro Rus + Service Pack 1
- PHP 4.0.5 (бралось с сайта php.net)


1) Идем в "Панель управления" --> "Установка и удаление программ" --> "Добавление и удаление компонентов Windows". Помечаем чекбокс "IIS".
Вставляем диск с дистрибутивом Windows 2000.
Ждем пока установится.

2) Распаковываем архив с дистрибутивом PHP в директорию, к примеру, c:\php\
Копируем файл php.ini-dist в директорию "\WinNT\". Находим его там, переименовываем в php.ini
Пока можно ничего не трогать в нем.
Копируем все файлы из директории c:\php\dlls\ в директорию "\WinNT\system32\".
Копируем файлы c:\php\php4ts.dll и c:\php\php4ts.lib в директорию "\WinNT\system32\"

3) Движемся в "Панель управления" --> "Администрирование" и запускаем "Диспетчер служб Интернета".
Выбираем вторую строку в левом окне. Там должно стоять имя вашей машины. Жмем правую кнопку мыши. Выбираем "Свойства".
Около раздела "Основные свойства" жмем "Изменить". Переходим на закладку "Фильры ISAPI".
Кнопка "Добавить" --> Имя фильтра == PHP, Исполняемый файл == c:\php4\sapi\php4isapi.dll
Переходим на закладку "Домашняя директория". Жмем баттон "Настройка". Жмем кнопку "Добавить".
Исполняемый файл == c:\php4\sapi\php4isapi.dll ; Расширение == .php
Должно быть отмечено "Все команды" и "Обработчик сценариев".
Жмем Ok столько раз, сколько попросят. Закрываем "Internet Information Services".

4) Движемся в "Панель управления" --> "Администрирование" и запускаем "Личный диспетчер Web".
Жмем "Дополнительно". Переходим на "Домашний каталог". Щелкаем (клювом).
Каталог == c:\inetpub\wwwroot
Отмечаем Чтение, Сценарии Жмем Ок.
Ставим галку "Задать документ, используемый по умолчанию", пишем туда index.php
Переходим в "Главное окно", жмем "остановить", потом "Запустить". Или, просто "Запустить".

5) Последний, и самый главный пункт. Смотрим на результаты наших трудов. Делаем файл index.php в каталоге c:\inetpub\wwwroot\
В файле пишем одну строку <? phpinfo(); ?>
Открываем броузер, пишем в строке состояния: 127.0.0.1
Долго ждем пока отработает такой простой скрипт. Убеждаемся что все работает (правда медленно), теперь удаляем IIS, устанавливаем Apache.

Оригинал заметки на: http://leosha.hoster.ru

7.5 Установка PHP 4.0.x в виде модуля для Apache под Win32

Скачиваем PHP самый свежий, который найдем.
Искать стоит на http://php.net/downloads.php

Распаковываем архив в любую директорию.
Берем файлы из этой директории: php4apache.dll и php4ts.dll и копируем их в директорию $SERVER_ROOT/modules
$SERVER_ROOT - это там, где лежит Apache.
Там есть директория modules.
Теперь, в httpd.conf (это файл настроек Apache)
пишем след. строки:

LoadModule php4_module modules/php4apache.dll
AddType application/x-httpd-php .php .phtml

Берем файл php.ini-dist из директории, где установлен PHP и копируем его в директорию, где установлен Windows (c:\windows\ , c:\WinNT\)
Переименовываем этот файл в php.ini
Если требуется - правим этот php.ini. Для начала, можно ничего не делать.

Все. Запускаем Apache. Проверяем работоспособность PHP.

PS. Стоит почитать статью по установке PHP+Apache+MySQL. Найти можно, например, на http://dklab.ru

7.6 Установка GD-lib под Win32.


8. Динамическое создание сайта (принципы и технологии)

Section Content

9. Типы данных

Section Content

9.1 Какие типы можно использовать?

PHP поддерживает следующие типы данных:
integer (целочисленные)
floating-point numbers или double (числа с плавающей запятой)
string (строки, текст)
array (массивы)
object (обьекты)
Преобразование типов происходит следующим образом. Если переменной при равнивается строка (текст в кавычках) то эта переменная становится строковой. Если-жы с ней совершается одна из многих математических функций или она приравнивается численой переменой, она становится численной, причем если приравниваетс яне целому значению - то станет типом double. Пример:

$foo = "0"; // $foo строка (ASCII 48)
$foo++; // $foo тоже строка "1" (ASCII 49)
$foo += 1; // $foo теперь integer (2)
$foo = $foo + 1.3; // $foo теперь double (3.3)
$foo = 5 + "10 паросят"; // $foo теперь снова integer (15)
$foo = 5 + "10 ящиков"; // $foo и по прежнему integer (15)
значение в скобках - результирующее значение переменной
Преобразовывать типы можно чистА в сишном стиле:

$foo = 10; // $foo это integer
$bar = (double) $foo; // $bar это double
Разрешенный преобразования:
(int), (integer) - cast to integer
(real), (double), (float) - cast to double
(string) - cast to string
(array) - cast to array
(object) - cast to object
К стати, определить тип переменной можно функциями gettype(), is_long(), is_double(), is_string(), is_array() и is_object().

9.2 Что такое константы?

Вы можете использовать не только переменный но и константы с помощью функции define(). Взгляните на следующий пример:

define("CONSTANT", "Hello world."); echo CONSTANT;
обратите внимание на то, что перед именем константы не пишется символа переменной $ и это правильно.

Ну и напоследок список предопределенных констант.
__FILE__ Имя файла выполняемого скрипта.
__LINE__ Колличество линий, интерптетированный на данный момент в этом скрипте.
PHP_VERSION Тут хранится версия PHP. Например: '3.0.8-dev'.
PHP_OS Имя операционной системы, на которой выполняется PHP-скрипт.
TRUE Истина.
FALSE Ложь.
E_ERROR Описывает случившуюся ошибку, продолжение работы после которой невозможно.
E_WARNING Описывает ошибку, после которой продолжается выполнения скрипта.
E_PARSE Описывает синтаксическую ошибку, рпи разоре интерпретатором текста скрипта.
E_NOTICE Просто какое-то сообщения от интерпретатора. Возможно ошибка, а возможно и нет.


10. Переменные языка

Section Content

10.1 Как использовать переменные?

Во-первых. Все переменные начинаются с символа $

Во-вторых существуют границы определения переменных. Например что-бы использовать глобальные переменные в функциях, необходимо их сначала декларировать как глобальные, иначе вы будете исопльзовать локальные переменные. Поясню на примере:

$a = 1; /* глобальное определение */
Function Test () {
$a=2;
echo $a; /* локальная переменная */
}
Test ();
echo $a;

Таким образом в функции используется локальная, собственная переменная и результатом прогарммы будет вывод чисел 2 и 1, а не 2 и 2, как некоторые могли подумать.

Ну а если вы хотите в функции использовать глобальные переменные, необходимо сделать так (декларировать с помощью оператора global):

$a = 1; /* глобальное определение */
Function Test () {
global $a;
$a=2;
echo $a; /* локальная переменная */
}
Test ();
echo $a;
Теперь в функции вы переопредилили глобальную переменную и вывод будет числа 2 и 2. Но есть и другой способ добраться до глобально-определенных данных - через ассоциативный массив $GLOBALS[]. Пример предыдущей программы, реализованный новым способом:

$a = 1; /* глобальное определение */
Function Test () {
$GLOBALS["a"]=2;
echo $a; /* локальная переменная */
}
Test ();
echo $a;
Обратите внимание переменная в массиве указывается без символа $

Кроме этог о PHP предоставляет возможность исопльзовать статические переменный. Все как в C/C++.

Function Test () {
static $a = 0;
echo $a;
$a++;
}
Test();
Test();
Test();

Результатом выполнения этого скрипта будет вывод чисел 0,1 и 2.

10.2 Что такое переменные переменных?

Скорее всего скоро вам понадобятся переменныес динамически (в ходе работы скрипты) изменяемым наименованием. Поясню на пример, что я имею ввиду:

$a = "hello"; $$a = "world";
Данная запись означает, что переменной с именем a мы присваиваем значение "hello". Следующей операцией переменной с именем, хранящимся в переменной с именем a, то есть - переменной hello мы присваиваем занчение "world"

echo "$a ${$a}";
тоже самое, что и

echo "$a $hello";
В результаты мы получим на экране hello world

Дело ненмого усложняется, если вы хотите использовать подобные массивы. Ведь есл вы запишете $$a[1] - интерпретатору надо будет знать, что использовать в качестве переменной - $a или $$a (имя, зранящееся в $a). В таком случаем вам прийдется исопльзовать следующий синтаксис - ${$a[1]} в случае, если вы хотите использовать переменную с именем, зранящимся в массиве $a с индексмо 1 и ${$a}[1] в другом случае (если вы хотите использовать элемент 1 массива с именем, зранящимся в переменной $a.

10.3 А зачем нужны переменные переменные ?

Что бы подставлять нужную тебе функцию к примеру...

10.4 Что такое статические(static) перененные ?

Another important feature of variable scoping is the static variable. A static variable exists only in a local function scope, but it does not lose its value when program execution leaves this scope. Consider the following example:

Другим важным свойствм области видимости переменных является возможность определения статических (static) переменных. Статические переменные можно определять только внутри функций, но они не потеряют своего значения после завершения функции. Рассмотрим пример:

function Test ()
{
$a = 0;
echo $a;
$a++;
}

This function is quite useless since every time it is called it sets $a to 0 and prints "0". The $a++ which increments the variable serves no purpose since as soon as the function exits the $a variable disappears. To make a useful counting function which will not lose track of the current count, the $a variable is declared static:

Эта функция бесполезна как счетчик. При каждом вызове переменная $a будет установлена в 0 и выведена на печать. $a++ увеличит переменную а на 1, но значение переменной $a будет утеряно после выхода из функции. Надо объявить переменную $a как статическую для того, чтобы она выполняла роль счетчика и ее значение не терялось после завершения функции:

function Test()
{
static $a = 0;
echo $a;
$a++;
}

Now, every time the Test() function is called it will print the value of $a and increment it.

Теперь при каждом вызове функции Test() - она будет выводить на печать значение переменной $a и увеличивать его на 1.

Static variables also provide one way to deal with recursive functions. A recursive function is one which calls itself. Care must be taken when writing a recursive function because it is possible to make it recurse indefinitely. You must make sure you have an adequate way of terminating the recursion. The following simple function recursively counts to 10, using the static variable $count to know when to stop:

Статические переменные ведут себя точно так же при рекурсивном вызове функций. Функция называется рекурсивной, если она вызывает саму себя. Вы должны быть очень аккуратны при написании рекурсивных функций, поскольку можно получить бесконечную рекурсию при неправильном подходе. Выдолжны быть уверены в том, что ваша рекурсия будет прервана в какой-либо момент. Следующий пример демонстрирует рекурсивный счетчик до 10, используя статическую переменную $count для того, чтобы прервать рекурсию.

function Test()
{
static $count = 0;

$count++;
echo $count;
if ($count < 10) {
Test ();
}
$count--;
}

10.5 Как передать скрипту параметры, при запуске из командной строки?

Скрипты написанные на PHP можно запускать и при отсутствии Web-сервера. Чтобы передать при вызове такому скрипту параметры, есть несколько путей:

1) >php.exe file.php 10 20

file.php содежит:
<? echo "$argv[1] \n $argv[2]"; ?>
Выведет

X-Powered-By: PHP 4.0.5
Content-type: text\html
10
20

2) >php.exe -f file.php &a=10&b=20

file.php содежит:
<? echo "$a \n $b"; ?>
Выведет

10
20

10.6 Как определить браузер и его версию с которого запрашивается скрипт?


11. Операторы

Section Content

11.1 Как производить вычисления?

АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ
А рифметических операция в PHP всего пять, вот они:

$a + $b
$a - $b
$a * $b
$a / $b
$a % $b
Я думаю здесь все ясно. Ну можеттолко поясню последнюю операцию, результат ее выполнения остаток от деления $a на $b.

СТРОКОВЫЕ ОПЕРАЦИИ
Ха! А здесь и того меньше! Чисто строковой операцией считается операция сложения двух строк. Причем выглядит она довольно необычно, но практично:

$c = $a . $b;
То есть символом этой операции является точка. А результатом ее выполнения будет обыкновенная строка, состоящая из $a и $b

ОПЕРАЦИЯ ПРИСВАИВАНИЯ
Ну тут вообще ничего сложного, она всегда одна, это знак '=' и естественно этот знак означает, что переменной с лева от него будет присвоенное значение, полученное в результате выполнения каких либо операций или переменной/константы с правой стороны. Причем тут возомжно некоторый С++ -ные варианты, как-то:

$a = ($b = 4) + 5; // $a будет равна 9, а $b 4-м.
$a += 5; // аналогично $a = $a + 5;
$b = "Привет ";
$b .= "всем!"; // аналогично $b="Привет всем!"
ДВОИЧНЫЕ ОПЕРАЦИИ
Аа... и тут вообщем-то ничего нового:

$a & $b Побитовое И (AND)
$a | $b Побитовое ИЛИ (OR)
~ $a Исключающее или (XOR)
$a << $b Сдвиг влево на $b битов
$a >> $b Сдвиг вправо на $b битов
ЛОГИЧЕСКИЕ ОПЕРАЦИИ
Все тоже...

$a and $bИ (AND)
$a && $bТоже самое, что и предыдущее
$a or $bИли (OR)
$a || $bТоже, что и предыдущее
$a xor $bИсключающее или (XOR)
! $aИнверсия (NOT)
ОПЕРАЦИИ СРАВНЕНИЯ
Здесь будет что-нибудь новое или нет? Даже комментировать эти операции не буду...

$a == $b
$a != $b
$a < $b
$a > $b
$a <= $b
$a >= $b
В PHP существует также, как и в C++, тринарный оператор '?:'. Кто незнает - обьясню на примере.

$res= (expr1) ? (expr2) : (expr3);
Результатом этой операции будет значение (expr2), в том случае, если expr1==1 и значение expr3 в противном случае. Где все эти expr1, expr2, expr3 - являются переменными/константами или математиескими выражениями. Такая запись по сути своей аналогична следующей:

if (expr1) $res=(expr2); else $res=(expr3);
но естественно более лаконична.


12. Выражения (+ошибки)

Section Content

12.1 Какие возможности управлять логикой?

Мне кажется не стоит попусту лить воду и описывать тут и так всем известные из других языков програмирования структуры управления. Вместо этого я приведу их полный список и все методы их использования.

IF
Структура:

if (выражение)
    блок_выполнения
Пример использования:

if ($a > $b)
print "a больше, чем b";

if ($a > $b) {
print "a больше, чем b";
$b = $a;
}

ELSE
Пример использования:

if ($a > $b) {
print "a больше, чем b";
} else {
print "a не больше, чем b";
}
elseif
Интересный оператор. Он применяется в случае, когда вам необходимо использовать IF сразу после ELSE

Пример использования:

if ($a > $b) {
print "a is bigger than b";
} elseif ($a == $b) {
print "a is equal to b";
} else {
print "a is smaller than b";
}
if(): ... endif;
Тоже довольно необычная структура. Смысл ее в том, что если условие, записанное в круглых скобах оператора IF оказалось истинной, то будет выполняться весь код, начиная от двоеточия ':' то команда ENDIF;

Пример использования:

<?php if ($a==5): ?>
A = 5
<?php endif; ?>
Или вот еще с использованием вышеописанного оператора ELSEIF

if ($a == 5):
print "a equals 5";
print "...";
elseif ($a == 6):
print "a equals 6";
print "!!!";
else:
print "a is neither 5 nor 6";
endif;
WHILE
Структура:

while (выражение): блок_выполнения ... endwhile;
И примерчик:

$i = 1;
while ($i <= 10) {
print $i++;
}
do.. while
Вообщем-тоничего необычного - цикл, как цикл. Выполняется блок выполнения до тех пор, пока справедливо выражение. Структура:

do блок_выполнения while (выражение);
FOR
Точно такой-же цикл как и в C++. Структура:

for (выражение1; выражение2; выражение3)
блок_выполнения
Хотя - нет. Есть в PHP еще одно дополнение. Структура:

for (выражение1; выражение2; выражение3):
блок_выполнения; ...; endfor;
Обратите внимание, на двоеточие перед блоком выполнения.

break
Старо как мир. Этот оператор позволяет выскакивать из любого цикла (for, while, do.. while) до окончания его выполнения. Пример:

$i = 0;
while ($i < 10) {
if ($arr[$i] == "stop") {
break;
}
$i++;
}
continue
Тоже ничего нового. Этот оператор позволяет пропустить дальнейшее действия блока_выполнения любого цикла и продолжить выполнение с нового круга. Пример:

while (выражение) {
if (выражение2)
continue;
действие;
};
Такая програма аналогична следующей, без использования continue:

while (выражение) {
if (!выражение2)
     действие;
};
switch
Часто очень необходимый оператор выбора. Хотя все его и так знают, попробую представить ясный пример. Допустим у вас есть следующий участок в программе:

if ($i == 0) {
print "i равно 0";
} else
if ($i == 1) {
print "i равно 1";
} else
if ($i == 2) {
print "i равно 2";
} else
print " ниодно условие не прошло"

Сэкономить время выполнения данного участка, а так-же представить его более логичным способом и поможет нам этот оператор. Следующий пример совершает действия, аналогичные предыдущему, но в более красивой форме:

switch ($i) {
case 0:
print "i равно 0";
break;
case 1:
print "i равно 1";
break;
case 2:
print "i равно 2";
break;
default:
print " ниодно условие не прошло"
}
в таком представлении есть и еще одно преимущество. Если вы не поставите оператор break например перед case 1:, то в случае, когда $1 будет равен нулю после вывода на экран сообщения об этом программа пойдет дальше и выведет также сообщение о тов, что $I равна еще и 1 и только после, встретив break; продолжит свое выполнение за пределами switch

require
Этот оператор действует примерно так-же как и #include в C++. Файл, указанный в кавычках включается в скрипт и выполняется, но только однажды. В файле, включаемом оператором require резонно хранить какие-то даные, необходимые для многих скриптов и соответсвенно влкючать его в эти "многие" скрипты. Структуа его такая:

require 'header.inc';
include
Структура:

include 'func.inc';
Этот оператор позволяет включать код, содержащийся в указанном файле (func.inc в нашем случае) и выполнять его столько раз, сколько программа встречает этот оператор. То есть. Например в файле func.inc у нас хранится программа вывода на экран определенных параметров. Ну и каждый раз, когда нам нужно будет выводить эти параметры мы будем вставлять в текст нашей основной программы include 'func.inc', то есть это в принципе тоже самое, как если-бы мы везьде в таких случаях вставили-бы текст, содеражийся в файле func.inc

Обратите внимание. Разница между include и require довольно существенная, поэтому поэкспереминтируйти с ними сами, если вы ее так и не усмотрели.


13. HTML Формы

Section Content

13.1 HTML Формы (GET и POST)

После заполнения пользователем HTML формы PHP может получить доступ к этим данным через переменные, имеющие такие-же название, что и поля в форме. Как всегда продемонстрирую на примере:

<form action="foo.php3" method="post">
Name: <input type="text" name="name">
<input type="submit">
</form>
Значит после того, как пользователь нажмет в форме кнопку submit в php-скрипт foo.php3 методом post передадутся данные из формы, а обратиться, например к текстовому полю, из этого скрипта можно будет через переменную $name. Кроме того, можно использовать и массивы в качестве названий полей.

<form action="array.php" method="post">
Name: <input type="text" name="personal[name]">
Email: <input type="text" name="personal[email]">
Beer:
<select multiple name="beer[]">
<option value="warthog">Warthog
<option value="guinness">Guinness
</select>
<input type="submit">
</form>
В результате это скрипт (array.php) может вывести полученные результаты так:

echo "Имя: ".$personal["name"];
echo "Email: ".$personal["email"];
for ($i=0;$i<sizeof($beer);$i++)
echo $beer[$i]."<br>";
Кроме этого, как известно в форме в качестве submit-кнопки можно применять картику <input type=image src="image.gif" name="sub">. В таком случаем скрипту возвращаются еще две дополнительных переменных, содержащих координаты точки, на которой кликнули мышкой. Это sub_x и sub_y.
----
Дополнено DVA
----
Если включена в настройках опция track_vars, то в зависимости от способа передачи у вас появится ассоциативный массив с именем $HTTP_POST_VARS, (Для POST) или $HTTP_GET_VARS (Для GET), который будет содержать все переменные переданные из формы. Например скрипт, покаывающий, что именно нам передаёт форма, может выглядеть так:

<?
function show($value, $name)
{
echo "Переданна переменная <b>$name</b> = $value<br>";
}
array_walk($HTTP_POST_VARS,'show');
// Или array_walk($HTTP_GET_VARS,'show');
?>

13.2 Передаются ли в скрипт значения соответствующие кнопкам формы?

В скрипт передаются все именованные элементы форм. Таким образом, если у кнопки указан атрибут name="button_name", то будет установлена соотвествующая переменная в запросе, а ее значение будет равно атрибуту value. что характерно, это текст на кнопке.

Если у кнопки опущен элемент name, то соответствующей переменной не будет установлено в запросе.

Обратите внимание что для того, чтобы эти переменные автоматически создавались, необходимо выполнение следующих параметров кофигурации:

register_globals boolean
По умолчанию включено.
Если выключено, то переменные не создаются.


gpc_order string
По умолчанию GPC.
Определяет нужно ли принимать GET, POST и COOKIE.
Если оставить, например, GC то данные переданные по POST не будут определены.


track_vars boolean
По умолчанию включено.
Определяет создавать ли глобальные массивы $HTTP_ENV_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, и $HTTP_SERVER_VARS

13.3 Как сделать <SELECT> элемент с данными взятыми из MySQL?

Уровень подготовки читателя:     Ламер со стажем.

Решение:

Для примера создадим таблицу "country" для хранения названий стран и соответствующего им кода ISO (полагается что БД "testbase" уже создана):

CREATE TABLE country (
country_id smallint(6) NOT NULL auto_increment,
country_iso_code char(2) NOT NULL,
country_name varchar(60) NOT NULL,
PRIMARY KEY (country_id),
UNIQUE country_id (country_id, country_iso_code, country_name),
KEY country_id_2 (country_id, country_iso_code, country_name)
);


Теперь, занесем в нее немножко данных:

<?php
$country = array(); /* Ассоциативный массив где: индекс=код ISO, значение=страна */

$country[ 'AF' ] = 'Afghanistan';
$country[ 'AL' ] = 'Albania';
$country[ 'DZ' ] = 'Algeria';
$country[ 'AD' ] = 'Andorra';
$country[ 'AO' ] = 'Angola';
$country[ 'AQ' ] = 'Antarctica';
$country[ 'AR' ] = 'Argentina';
$country[ 'AM' ] = 'Armenia';
$country[ 'AU' ] = 'Australia';
$country[ 'AT' ] = 'Austria';
$country[ 'AZ' ] = 'Azerbaijan';
$country[ 'BS' ] = 'Bahamas';
$country[ 'BH' ] = 'Bahrain';
$country[ 'BD' ] = 'Bangladesh';
$country[ 'BY' ] = 'Belarus';
$country[ 'BE' ] = 'Belgium';
$country[ 'BJ' ] = 'Benin';
$country[ 'BM' ] = 'Bermuda';
$country[ 'BT' ] = 'Bhutan';
$country[ 'BO' ] = 'Bolivia';
$country[ 'BA' ] = 'Bosnia-Herzegovinia';
$country[ 'BW' ] = 'Botswana';
$country[ 'BR' ] = 'Brazil';
$country[ 'BN' ] = 'Brunei Darussalam';
$country[ 'BG' ] = 'Bulgaria';
$country[ 'BF' ] = 'Burkina Faso';
$country[ 'BI' ] = 'Burundi';
$country[ 'KH' ] = 'Cambodia';
$country[ 'CM' ] = 'Cameroon';
$country[ 'CA' ] = 'Canada';
$country[ 'CV' ] = 'Cape Verde';
$country[ 'CF' ] = 'Central African Republic';
$country[ 'TD' ] = 'Chad';
$country[ 'CL' ] = 'Chile';
$country[ 'CN' ] = 'China';
$country[ 'CO' ] = 'Colombia';
$country[ 'KM' ] = 'Comoros';
$country[ 'CG' ] = 'Congo';
$country[ 'CR' ] = 'Costa Rica';
$country[ 'HR' ] = 'Croatia';
$country[ 'CU' ] = 'Cuba';
$country[ 'CY' ] = 'Cyprus';
$country[ 'CZ' ] = 'Czech Republic';
$country[ 'DK' ] = 'Denmark';
$country[ 'DJ' ] = 'Djibouti';
$country[ 'DO' ] = 'Dominikanische Republik';
$country[ 'EC' ] = 'Ecuador';
$country[ 'EG' ] = 'Egypt';
$country[ 'SV' ] = 'El Salvador';
$country[ 'GQ' ] = 'Equatorial Guinea';
$country[ 'EE' ] = 'Estonia';
$country[ 'ET' ] = 'Ethiopia';
$country[ 'FЦ' ] = 'Faroe Islands';
$country[ 'FI' ] = 'Finland';
$country[ 'FR' ] = 'France';
$country[ 'GF' ] = 'French Guiana';
$country[ 'PF' ] = 'French Polynesia';
$country[ 'GA' ] = 'Gabon';
$country[ 'GM' ] = 'Gambia';
$country[ 'GE' ] = 'Georgia';
$country[ 'DE' ] = 'Germany';
$country[ 'GH' ] = 'Ghana';
$country[ 'GI' ] = 'Gibraltar';
$country[ 'GR' ] = 'Greece';
$country[ 'GL' ] = 'Greenland';
$country[ 'GP' ] = 'Guadeloupe';
$country[ 'GT' ] = 'Guatemala';
$country[ 'GN' ] = 'Guinea';
$country[ 'GW' ] = 'Guinea-Bissau';
$country[ 'GY' ] = 'Guyana';
$country[ 'HT' ] = 'Haiti';
$country[ 'VA' ] = 'Holy See';
$country[ 'HN' ] = 'Honduras';
$country[ 'HK' ] = 'Hong Kong';
$country[ 'HU' ] = 'Hungary';
$country[ 'IS' ] = 'Iceland';
$country[ 'IN' ] = 'India';
$country[ 'ID' ] = 'Indonesia';
$country[ 'IQ' ] = 'Irak';
$country[ 'IR' ] = 'Iran (Islamic Republic of)';
$country[ 'IE' ] = 'Ireland';
$country[ 'IL' ] = 'Israel';
$country[ 'IT' ] = 'Italy';
$country[ 'CI' ] = 'Ivory Coast';
$country[ 'JM' ] = 'Jamaica';
$country[ 'JP' ] = 'Japan';
$country[ 'JO' ] = 'Jordan';
$country[ 'KZ' ] = 'Kazakhstan';
$country[ 'KE' ] = 'Kenya';
$country[ 'KP' ] = 'Korea (Democratic Peoples Republic of)';
$country[ 'KR' ] = 'Korea (Republic of)';
$country[ 'KW' ] = 'Kuwait';
$country[ 'LA' ] = 'Laos ';
$country[ 'LV' ] = 'Latvia';
$country[ 'LB' ] = 'Lebanon';
$country[ 'LS' ] = 'Lesotho';
$country[ 'LR' ] = 'Liberia';
$country[ 'LI' ] = 'Liechtenstein';
$country[ 'LT' ] = 'Lithuania';
$country[ 'LU' ] = 'Luxembourg';
$country[ 'MO' ] = 'Macau';
$country[ 'MG' ] = 'Madagascar';
$country[ 'MW' ] = 'Malawi';
$country[ 'MY' ] = 'Malaysia';
$country[ 'MV' ] = 'Maldives';
$country[ 'ML' ] = 'Mali';
$country[ 'MT' ] = 'Malta';
$country[ 'MQ' ] = 'Martinique';
$country[ 'MR' ] = 'Mauritania';
$country[ 'MU' ] = 'Mauritius';
$country[ 'MX' ] = 'Mexiko';
$country[ 'MD' ] = 'Modavia';
$country[ 'MC' ] = 'Monaco';
$country[ 'MN' ] = 'Mongolia';
$country[ 'MA' ] = 'Morocco';
$country[ 'MZ' ] = 'Mozambique';
$country[ 'NA' ] = 'Namibia';
$country[ 'NP' ] = 'Nepal';
$country[ 'NL' ] = 'Netherlands';
$country[ 'NC' ] = 'New Caledonia';
$country[ 'NZ' ] = 'New Zealand';
$country[ 'NI' ] = 'Nicaragua';
$country[ 'NE' ] = 'Niger';
$country[ 'NG' ] = 'Nigeria';
$country[ 'NO' ] = 'Norway';
$country[ 'PK' ] = 'Pakistan';
$country[ 'PA' ] = 'Panama';
$country[ 'PG' ] = 'Papua New Guinea';
$country[ 'PY' ] = 'Paraguay';
$country[ 'PE' ] = 'Peru';
$country[ 'PH' ] = 'Philippines';
$country[ 'PL' ] = 'Poland';
$country[ 'PT' ] = 'Portugal';
$country[ 'PR' ] = 'Puerto Rico';
$country[ 'RO' ] = 'Romania';
$country[ 'RU' ] = 'Russian Federation';
$country[ 'RW' ] = 'Rwanda';
$country[ 'SM' ] = 'San Marino';
$country[ 'SA' ] = 'Saudi Arabia';
$country[ 'SN' ] = 'Senegal';
$country[ 'SC' ] = 'Seychelles';
$country[ 'SL' ] = 'Sierra Leone';
$country[ 'SG' ] = 'Singapore';
$country[ 'SK' ] = 'Slovakia';
$country[ 'SI' ] = 'Slovenia';
$country[ 'SB' ] = 'Solomon Islands';
$country[ 'SO' ] = 'Somalia';
$country[ 'ZA' ] = 'South Africa';
$country[ 'ES' ] = 'Spain';
$country[ 'LK' ] = 'Sri Lanka';
$country[ 'SD' ] = 'Sudan';
$country[ 'SR' ] = 'Suriname';
$country[ 'SZ' ] = 'Swaziland';
$country[ 'SE' ] = 'Sweden';
$country[ 'CH' ] = 'Switzerland';
$country[ 'SY' ] = 'Syrian Arab Republic';
$country[ 'TW' ] = 'Taiwan';
$country[ 'TZ' ] = 'Tanzania';
$country[ 'TH' ] = 'Thailand';
$country[ 'MK' ] = 'The Former Yugoslav Republic of Macedonia';
$country[ 'TG' ] = 'Togo';
$country[ 'TT' ] = 'Trinidad and Tobago';
$country[ 'TN' ] = 'Tunisia';
$country[ 'TR' ] = 'Turkey';
$country[ 'UG' ] = 'Uganda';
$country[ 'UA' ] = 'Ukraine';
$country[ 'AE' ] = 'United Arab Emirates';
$country[ 'GB' ] = 'United Kingdom';
$country[ 'US' ] = 'United States';
$country[ 'UY' ] = 'Uruguay';
$country[ 'UZ' ] = 'Uzbekistan';
$country[ 'VE' ] = 'Venezuela';
$country[ 'VN' ] = 'Vietnam';
$country[ 'YE' ] = 'Yemen';
$country[ 'YU' ] = 'Yugoslavia';
$country[ 'ZR' ] = 'Zaire';
$country[ 'ZM' ] = 'Zambia';
$country[ 'ZW' ] = 'Zimbabwe';

$link = mysql_connect("localhost","","") or die ("Не могу соедениться с MySQL"); /* Не забудте изменить! */

mysql_select_db("testbase",$link) or die ("Не могу выбрать базу");

while(list($key,$name)=each($country)){ /* Пользователи PHP4 могуть использовать foreach($country as $key => $name){...} */

if(!mysql_query("INSERT INTO country (country_iso_code, country_name) VALUES ('$key', '$name')",$link))
{

echo "<pre>Ошибка ввода строки $key :".mysql_error($link)."</pre>";

     die;

    }
}

echo "Everything is nishtyak!";
            
?>

Теперь, если все прошло без ошибок :), можно приступить к главному. Для начала решим в каком виде мы хотели бы видеть дискриптор <select>? Положим что вам быть не раз придется решать подобную задачу, да и просто ради удобства выделим наш код в отдельную функцию, которая будет находится в отдельном файле и подключаться по мере необходимости.

Назовем ее незатейливо - "select":

<!-- select.inc.php -->

<?php

function select($result, $value_index = 0, $text_index = 1, $selected = 1, $param=array()){

/*
$result результат запроса SQL
$value_index индекс в массиве для значения VALUE (необязательный)
$text_index индекс в массиве для текстового значения OPTION (необязательный)
$selected индекс в массиве для выбранного значения OPTION (необязательный)
$parametrs ассоциативный массив атрибутов дискриптора SELECT (необязательный)
*/



echo "<SELECT";

if (isset($param)){

while (list($param_name, $param_value) = each($param)){ /* Добавляем переданные через массив атрибуты (можно использовать foreach() см. выше) */

if($param_value == "multiple"){        /* Здесь, по необходимости, можно добавить обработку JS */
echo " $param_value";
continue;
}

echo " $param_name=\"$param_value\"";

}
}
echo ">";


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

if ($row[$value_index] == $selected){

echo "<OPTION VALUE=$row[$value_index] SELECTED>$row[$text_index]</OPTION>\n";

}

echo "<OPTION VALUE=$row[$value_index]>$row[$text_index]</OPTION>\n";

}

echo "</SELECT>";

}

Теперь оттестируем нашу функцию:

<!-- test_select.php -->

<?php

include("select.inc.php"); //Убедитесь, что оба файла находятся в одном каталоге

$host = "localhost";        /* Не забудте изменить! */
$user = "";            
$pass = "";                
$db = "testbase";        


if (!$link = mysql_connect ($host, $user, $pass)){

echo "Не могу соедениться с MySQL";
die;

}

If (!mysql_select_db($db, $link)){

echo "Не могу выбрать базу $db. Ошибка: ".mysql_error($link);
die;

}

if (!$result = mysql_query("SELECT * FROM country")){

echo "Ошибка запроса ".mysql_error($link);
die;
}

/* Теперь в переменной $result находится результат выборки из таблицы "country". Важно заметить, что в результате могут быть задействованы множество полей таблицы (в нашем случае 3), так как мы полагаем, что запрос используется не только для генерации нашей менюшки, но еще для каких-то целей; а нам для <select>'а нужно только 2, поэтому в качестве параметров фунции могут передаваться также и номера полей. Помните, что после SQL-запроса вида "SELECT * FROM table_name", в результате, поля будут располагаться так, как они были расположены в таблице при ее создании (В нашем случае порядок такой: country_id country_iso_code country_name) Так что перед тем как передавать эти параметры, убедитесь в том, что вы представляете себе структуру вашей таблицы, либо не используйте (*) а перечисляйте поля ручками :) Можно,также использовать
функции mysql_list_fields() , mysql_num_fields(),, mysql_field_name(). По умолчанию установлены данные из 1-го поля для значения VALUE, из второго - для текстового значения OPTION. */

echo "<FORM>";

$discriptor_param = array (name => "select_1",
size => "5", multiple);        /* Передаем атрибуты, для подробной информации читайте спецификацию HTML */


$value_index=1; //т.е. для значения VALUE выводить строки из поля country_iso_code
$text_index=2; //т.е. для текстового значения OPTION выводит строки из поля country_name
$selected="RU"; //установить выбранным опцию где VALUE="RU"

select($result, $value_index, $text_index, $selected, $discriptor_param);

echo "\n<BR>\n<BR>\n";

/* И еще разок: */

$discriptor_param = array (name => "select_2");


$value_index=0;     /* т.е. для значения VALUE выводить строки из поля country_id */
$text_index=2;         /* т.е. для текстового значения OPTION выводит строки из поля country_name */
$selected="136";     /* установить выбранным опцию где VALUE="136" */

mysql_data_seek($result,0);     /* сбросим внутренний указатель результата */

select($result, $value_index, $text_index, $selected, $discriptor_param);

echo "</FORM>";

mysql_free_result($result);     //на любителя
mysql_close($link);         //Также на любителя :)

?>

Можно также, доработать функцию и добавить в нее обработку переданного в качестве параметра JS. Функция не совсем :) оптимальна, но главное, что она показывает как решать подобные задачи. Удачи! <-- рифма :)

13.4 Как сделать List/Menu (дропдаун меню) элемент с данными взятыми из MySQL (PHPLIB)?

<?
function languagelist($lang)
{
//I am use phplib for acces to mysql-databases ....
$languagedb = new db;

$query="use ".$languagedb->Database;
$languagedb->query($query);
if($languagedb->query_id()==0)
{
echo("Database not using");
halt;
};

$query="select * from lang";
$languagedb->query($query);
$count=$languagedb->num_rows();
if($count>0)
{
for($i=0;$i<$count;$i++)
{
$languagedb->next_record();
echo("<option value='".$languagedb->f('id')."'");
if($lang==$languagedb->f('id'))echo(" selected");
echo(">".$languagedb->f('name')."</option>");
};
};
};
?>
<select name="lang" style={width=108pt}>
<option value="">Please select one</option>
<?
@languagelist($lang);
?>
</select>

13.5 Как проверить был ли отмечен CHECKBOX в форме?

У Вас есть форма такого типа:

<form action="page.php" method="POST">
...
<input type="checkbox" name="checkme" value="yo">
...
<input type="submit" value="ok">
</form>

После нажатия на "ok" данные передаются скрипту page.php. Здесь выполняем проверку на предмет, был ли отмечен чекбокс:

<?
...

if (isset($checkme) && strlen($checkme)>0) // здесь "checkme" - имя чекбокса
{

... // если чекбокс отмечен, выполняем какие-то действия

}

...
?>


Решение от Roman Korobeinikov <shainsky@mail.ru>

Есть еще один способ сделать это, как мне кажется, более простой:
в форме _перед_ тегом <input type='checkbox'> поместить тег
<input type='hidden'> с тем же самым значением параметра 'name':
<form ...>
...
<input type="hidden" name="checkme" value="0">
<input type="checkbox" name="checkme" value="1">
...
</form>

Теперь если checkbox взведен, в переменной $checkme передастся "1",
в противном случае "0".








13.6 Как загрузить файл на сервер через броузер (сделать upload) ?

Немного теории. Это нужно, для понимания что и как работает.

- вы в броузере указываете файл для загрузки на сервер;
- броузер передает выбранный файл на сервер;
- PHP-интерпретатор на сервере записывает полученный файл во временную директорию. Причем, имя, под которым записывается файл, может быть абсолютно случайным. Это только под Windows PHP пишет файл с именами подобными <b>PHP2<b>.
Нам, в принципе, вовсе не обязательно знать под каким именно именем загруженный файл хранится во временной директории. Почему не надо знать? Потому что, вполне достаточно того, что PHP "знает". И, в любом случае, после завершения работы скрипта, этот файл удаляется.
- Вы говорите PHP, что загруженный файл надо скопировать из временной директории туда, куда хотите.

На этом, сам процесс "аплоада" можно считать завершенным.

Что вы потом сделаете с этим файлом, вопрос другой.
И еще: все трудности под Win32 связанные с "непонимаем" системой конструкции вида "\\PHP2" (кто сталкивался, поймет) кроются в файле php.ini (php3.ini) Лично у меня, это выглядит так (получено опытным путем):
upload_tmp_dir = "f:/tmp/" - php3.ini
upload_tmp_dir = "f:\tmp" - php.ini
С такими настройками, никаких проблем я не замечал. Попробуйте.

Теперь про ограничение размера загружаемого файла. Конечно, и в php.ini есть параметр upload_max_filesize, можно ограничить и размер и тип указанием соответствующих параметров в теге FORM, но, в любом из этих случаев мы получим ошибку, которую не сможем обработать. Что не здорово. Поэтому, удобней ограничивать размер в самом скрипте.
НО: РАЗМЕР файла невозможно узнать до ПОЛНОЙ загрузки файла на сервер. Никаким способом.

Также, при uploade, до ЗАВЕРШЕНИЯ загрузки, файл хранится в памяти, потом пишется во временную директорию, и, еще раз напомню, сразу удаляется из temp по завершению работы скрипта. Вообщем, с помощью PHP не получится сделать индикатор загрузки файлов.

Итак, сначала у нас файл upload.html примерно такого вида.

<html><head><title>Upload</title></head><body>

<form action=upload.php method=post enctype=multipart/form-data>
<!-- обратите внимание на enctype!!! -->

<input type=file name=file1>
<br>
<input type=file name=file2>
<br>
<input type=submit name=upload value="Загрузить">

</form></body></html>

Теперь, сам скрипт.

<?

$max_size = 65535;
// максим. размер в БАЙТАХ
$type_1 = "application/x-zip-compressed";
$type_2 = "text/plain";
// типы файлов, которые мы хотим принимать

$path = "/home/test/frob";
// каталог, куда сохраняем файлы

if ( ($file1 == "none") && ($file2 == "none") ) {
echo "Не выбрано ни одного файла!"; exit; }

if ($file1_size > $max_size)

{ echo "Неверный размер! Файл $file1_name НЕ загружен."; }

elseif ( ($file1_type != $type_1) AND ($file1_type != $type_2) )
{ echo "Неверный тип! Файл $file1_name ($file1_type) НЕ загружен."; }

else {
copy ("$file1", "$path/$file1_name");
echo "
Вы загрузили файл $file1_name. Этот файл сохранен в каталоге $path<br>\n
Размер файла - $file1_size байт<br>\n
Тип файла - $file1_type<br>\n<br><br><br>
";
}

if ($file2_size > $max_size)

{
echo "Неверный размер! Файл $file2_name НЕ загружен.";
}

elseif ( ($file2_type != $type_1) AND ($file2_type != $type_2) )
{
echo "Неверный тип! Файл $file2_name НЕ загружен.";
}

else {
copy ("$file2", "$path/$file2_name");
echo "
Вы загрузили файл $file2_name. Этот файл сохранен в каталоге $path<br>\n
Размер файла - $file2_size байт<br>\n
Тип файла - $file2_type<br>\n
";
}

?>

Итак, если Вы не удосужились открыть Manual, рассказываю (хотя, FAQ то он, конечно, FAQ, но чтение manual'ов никто не отменял):
В форме есть поле с type=file и именем file1.
При аплоаде, у нас возникают переменные:

$file1 - имя файла во временной директории;
$file1_name - исходное имя файла;
$file1_type - MIME тип файла;
$file1_size - размер файла;

Так, осталось рассмотреть случай, когда PHP работает в safe-mode. Т.е., если вы сделали все как написано, а вам говорят
Safe-mode restriction is effect... Или, про то, что невозможно выполнить команду copy() - попробуйте copy() заменить на move_uploaded_file().
Но, невозможность выполнить copy() может крыться и просто в том, что у PHP-процесса не хватает прав на запись в указанную вами директорию. В этом случае, вам проще всего спросить у своего администратора, какие права должны быть на директорию, в которую хочется записывать файлы.

Фу-у-у-у...

Последний штрих: на самом деле, если вам следует загрузить несколько файлов, не стоит пользоваться приведенной конструкцией. Лучше, обозвать поля для ввода файлов именем, например, file[], а потом разбирать полученный массив file[] уже.

13.7 В продолжение вопроса о Upload. Борьба с глюками.

Итак, вы сделали форму для аплоада файлов, вы сделали скрипт, который принимает загруженные файлы, но теперь возникла следующая проблема:
Картинки загружаются, но не показываеются. Бинарные файлы загружаются, но не запускаются (или, не распаковываются, если это архив).
Основная причина данной проблемы - Russian Apache.
Именно он (т.е. web-server) перекодирует все что ни попадя. Соответственно, после такой перекодировки, в файлах оказываются замещенными (перекодированными) некоторые символы. Что избежать подобного есть несколько решений:

1) В директории, где лежит скрипт для Upload'a делаем файл .htaccess в котором пишем:
CharsetDisable On

2) В файл httpd.conf дописать строки:
<Location />
CharsetRecodeMultipartForms Off
</Location>

Обычно, этого вполне достаточно для решения проблемы.

Оригинал - http://php.spb.ru/php/upload.html

13.8 Upload и PHP4

в PHP4 работа с upload'ами стала несколько иной.
теперь вся информация о залитых файлах хранится в массиве $HTTP_POST_FILES

для примера:
если у нас в форме было так: <input type="file" name="screenshot">
то информацию о файле надо смотреть здесь:
$HTTP_POST_FILES['screenshot']['name']
Оригинальное имя файла. Например "screen1.jpg"

$HTTP_POST_FILES['screenshot']['type']
mime type файла. Например "image/gif".

$HTTP_POST_FILES['screenshot']['size']
Размер файла в байтах

$HTTP_POST_FILES['screenshot']['tmp_name']
Временное имя файла на сервере.

В остальном смотри 13.6


14. HTTP Cookies

Section Content

14.1 Как использовать куки?

В PHP реалиован также простой способ работы с куками. С помоью функции SetCookie() можно их устанавливать, получать значения, как и в случае с формами - по имени переменной. В случае, если вы ожидаете получить несколько значений от куки имеет резон исопльзовать в качестве имени переменной - массив. Как в следующем примере.

SetCookie ("MyCookie[]", "Testing", time()+3600);
Существует только одно небольшое ограничение. Так-как куки - это часть HTTP заголовка их следует посылать самыми первыми. То есть грубо говоря, ваш скрипт должен начинаться с установки куки, а потом уже заниматься выводом html кода. Еще один пример, уже полноценного счетчика:

$Count++;
SetCookie ("Count", $Count, time()+3600);
SetCookie ("Cart[$Count]", $item, time()+3600);


15. Функции(область видимости, где применять)

Section Content

15.1 Что такое функция?

Функции, это, блин, очень полезная штука. Ща расскажу :)
Вот, допустим, тебе необходимо повторить одну и ту же операцию несколько раз, но с разными параметрами.
Как пример, возьмем вывод даты в селекте:
Function PrintMyDate ($from,$to) {
for ($i=$from;$i<=$to;$i++) {
$options.="<option value='$i'>$i\n";
}
return $options;
}
Теперь напечатаем 3 селекта с датами:
<select name=date1>
<?=PrintMyDate(1,31)?>
</select>
<select name=date2>
<?=PrintMyDate(1,12)?>
</select>
<select name=date3>
<?=PrintMyDate(2001,2002)?>
</select>
Вот. Быстро и понятно. А если этот делать "ручками" в html-e, то время уйдет не 3 минуты а все 30.

15.2 переменные внутри функций

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

Чтобы получить доступ г глобальным переменным их надо объявить с модификатором global, т.е.
global $<var1_name>[, $<var2_name> ... ];

причем если внутри функции делаете include то все переменные из этого include'а тоже надо объявить как global.

существует 'совсем' глобальный массив $GLOBALS - глобальные переменные, его можно не объявлять global.

Переменные можно объявлять с модификатором static - это обозначает, что значение переменной будет сохранено
между повторными вызовами функции.


16. Массивы (работа, практика, PHP4)

Section Content

16.1 эмуляция работы с массивами в PHP4 для PHP3

надо сделать несколько функций для того, чтобы работать с массивами в php3 так же удобно как в php4

// возвращает все ключи массива
function array_keys($all) {
    for (reset($all); list($k, $v) = each($all);) {
        $keys[] = $k;
    }
return $keys;
}
// возвращает все значения массива
function array_values($all) {
    for (reset($all); list($k, $v) = each($all);) {
        $vals[] = $v;
    }
return $vals;
}
// сливает два массива в один
function array_merge($to, $from) {
    for (reset($from); list($k, $v) = each($from);) {
        $to[$k] = $v;
    }
return $to;
}

// возвращает массив, состоящий из N элементов исходного массива
// начиная с M-того
function array_slice($all, $offset, $limit=0) {
    $ptr = reset($all);
for ($i=0; $i<$offset; $i++) $ptr = next($all);
if (!$limit) $limit = sizeof($all)-$offset;
else $limit = min(sizeof($all)-$offset, $limit);
for ($i=0; $i<$limit; $i++) {
    $ret[] = $ptr;
    $ptr = next($all);
}
return $ret;
}

если понадобится что-то еще пишите


17. Обьекты (работа, this, хранение)

Section Content

18. Строки (функции, использование, кеширование для вывода)

Section Content

19. Работа с файлами,DBF,CVS

Section Content

19.1 Как мне обновлять информацию из Excel?

Один из вариантов решения заключается в работе с файлом формата DBF.
Его понимает РНР и с ним работает Excel.
Для создания dbf файла, сохраняем выделенные ячейки как файл dBase.
<TABLE>
<?
$db= "excelfile.dbf"; // файл Excel, сохраненный как dBase
$open_db= dbase_open($db, 0); // открывает базу (read-only)
$fields= dbase_numfields($open_db); // Количество полей в таблице
$records= dbase_numrecords($open_db); // Количество строк в таблице

for ($i=1; $i<= $records; $i++) // Цикл "строки"
{
echo "<TR>";
$row= dbase_get_record($open_db, $i); // получает строку
for($a=0; $a< $fields; $a++) // Цикл "столбцы"
{
echo "<TD> $row[$a] </TD>";
}
echo "</TR>";
}
?>
</TABLE>

Если необходимо, можно занести таблицу в базу данных.
Для удобства, желательно перекодировать все символы функцией
convert_cyr_string().

Андрей Транский (Romantik)

Еще вариант сохранять как *.CSV Файл. А потом загружать в таблицу.


20. Работа с shared memory (чат)

Section Content

21. Работа с БД (враперы, тонкости, грамотное проектирование)

Section Content

21.1 Как мне вставить текст в поле description text, если в нем есть кавычки (')?

Нужно взять за правило!
Делать addslashes() при добавлении строки в таблицу и
stripslashes() при выборке.
И тогда будет намного меньше проблем.

Из мануала-
string addslashes (string str)

Returns a string with backslashes before characters that need to be quoted
in DATABASE QUERIES etc. These characters are single quote ('), double quote
("), backslash () and NUL (the null byte).


Написано же - DATABASE QUERIES, т.е. спец. для этого и придумано.


22. Работа с COM-обьектами

Section Content

22.1 Не могли бы Вы написать о новой возможности появившейся в PHP 4 - управление COM-объектами. Пример с запуском MS Word из PHP4 Manual почему-то не работает.


23. Сравнение баз MySQL & Postgres & MSSQL

Section Content

24. Графика (работа, GIF,PNG, шрифты, Flash)

Section Content

24.1 Галерея картинок

Читаем все имена в массив а потом формируешь урл из элементов массива в урле передаешь номер следующего или предыдущего номера картинки

<? $fd=@opendir("$id");} $i=0;
if($fd)
{ while($file=@readdir($fd))
{if($file!="." and $file!="..")
{$cornerimage[$i]=$file;$i++;}
else
{$r=100;}
}
@closedir($fd);$r=count($cornerimage);
?>

<font face=arial>
<table height=400 cellspacing=10 cellpadding=0 valign=top width=100% >
<tr>
<td aligh=center valign=top wrap><center>
<br><font size=-2>
<!--Модуль навигации цифрами-->
<? $j=0;
if($r<100)
{
for ($i=0;$i<($r);$i++)
{ if ($j<19)
{;?><a href=index.php3?idd=<?echo $i.'&id='.$id.'&mid='.$mid.'&lng='.$lng;?>><?echo $i+1;?></a>&nbsp;<?$j++;}
else
{$j=0;?><br><a href=index.php3?idd=<?echo $i.'&id='.$id.'&mid='.$mid.'&lng='.$lng;?>><?echo $i+1;?></a>&nbsp;<?}

};?> </font><?
}
else
{
}
;?>
</font> <hr>

<!-- Модуль вывода картинки и навигации стрелками-->
<?
if(!$idd )
{$idd=0;?><img src="<?$size=getimagesize("$id/$cornerimage[$idd]"); echo $id.'/'.$cornerimage[$idd].'" width="'.$size[0].'" height="'.$size[1].'"';$idd++;?>" alt="Picture"><br><hr><a href=index.php3?idd=<? echo $idd.'&id='.$id.'&mid='.$mid.'&lng='.$lng;?>>next >></a><?;}
else
{if($idd!=($r-1))
{$pidd=$idd-1;?><img src="<?$size=getimagesize("$id/$cornerimage[$idd]"); echo $id.'/'.$cornerimage[$idd].'" width="'.$size[0].'" height="'.$size[1].'"';$idd++;?>" alt="Picture"><br><hr><a href=index.php3?idd=<? echo $pidd.'&id='.$id.'&mid='.$mid.'&lng='.$lng;?>><< prev</a>&nbsp;<a href=index.php3?idd=<? echo $idd.'&id='.$id.'&mid='.$mid.'&lng='.$lng;?>>next >></a><?;}
else
{$pidd=$idd-1;?><img src="<?$size=getimagesize("$id/$cornerimage[$idd]"); echo $id.'/'.$cornerimage[$idd].'" width="'.$size[0].'" height="'.$size[1].'"';$idd++;?>" alt="Picture"><br><hr><a href=index.php3?idd=<? echo $pidd.'&id='.$id.'&mid='.$mid.'&lng='.$lng;?>><< prev</a>&nbsp;<?;}
}?>




</td> </center>
</tr>
</table>
</font>

здесь cornerimage[] -массив имен картинок
id - имя директории
idd - номер элемента массива
данный метод позволяет выводить картинки независимо от названий и типов файлов

24.2 Установка GD (под разные операционки)

24.3 Загрузка картинок в MySQL

24.4 Есть ли библиотека для вывода графиков, диаграмм?

Есть и даже не одна.

В первую очередь советую ознакомиться с
http://www.phplot.com

Также... можно пользоваться менее громоздкой библиотекой от Евгения Панина.
http://phpclasses.upperdesign.com/browse.html/package/94

И посмотреть соответсвующий раздел в репозитории
http://phpclasses.upperdesign.com/browse.html/class/11

Ну и на последок вот сюда заглянуть, будет тоже весьма полезно:
http://www.hotscripts.com/PHP/Scripts_and_Programs/Graphs_and_Charts/

SY Slach


25. Сеть (соскеты, whois, pop3, unr_encode)

Section Content

26. Почта (кодировки, вложения, IMAP, TWIG)

Section Content

26.1 Как отправлять почту в разных кодировках (WIN,KOI)?

К примеру Вам нужно отправить письмо в КОИ-8R
Добавляем заголовки для КОИ-8р

$extend_koi8r="\nContent-Type: text/plain;
charset=\"koi8-r\"\nContent-Transfer-Encoding: 8bit";
Конвертируем тело и заголовок

$email_body=convert_cyr_string($email_body,'w','k');
$email_subject=convert_cyr_string($plain_subject,'w','k');
Отправляем перекодированную почту

mail("адрес_получателя", "$email_subject", $email_body, "From: Info
<адрес_отпрвителя>".$extend_koi8r);

Для других кодировок ищите в мануале convert_cyr_string


27. Куки, хеадеры, сессии (авторизация, переменные окружения, эмуляция сессий)

Section Content

28. Безопасность (сервера, скриптов, SSL)

Section Content

28.1 Безопасность PHP+MYSQL+Apache

навеяно
http://phptalk.unet.ru/p/read.php?f=10&i=7429&t=7429&v=f

Итак был вопрос
.........
Есть у нас php скрипт, который обращается к MYSQL БД.
Если мы впишем в скрипт, условно говоря, root mysql'я,
то можем ли мы рассчитывать на безопасность действий (адекватность
и однозначность написанных операций) с БД?
Можем ли мы рассчитывать на безопасное хранение пароля в пхп-скрипте?
........

1) Лучше создать еще одного пользователя в базе mysql и урезать ему права.. -
2) Все поключения к базе из PHP осуществлять через так называемые конфигурационные файлы. Отсюдова подробнее.

Итак для доступа в mySQL через PHP создаем файлы дополнительные (конфигурационные) файлы
setup.php & config.php

File setup.php
<?
$dbName="dbName";
$dbUser="dbuser";
$dbPass="dbuserpass";
$dbServer="dbserver";
$adminmail="твое\@мыло";
?>
enf of file
далее создаем файл config.php
File config.php
<?
function db_err($handle, $message) {
printf("%s: %d: %s\n", $message, mysql_errno($handle),mysql_error($handle));
die();
}

function db_connect() {

global $dbName,$dbUser,$dbPass,$dbServer;
$dbh = mysql_connect($dbServer,$dbUser,$dbPass);
if(!$dbh) { db_err($dbh, "mysql_connect"); }
$res = mysql_select_db($dbName);
if(!$res) { db_err($dbh, "mysql_select_db"); }
return($dbh);

}

?>
end of file

потом выносим эти файлы за пределы сервера, и наконец подключаем эти файлы в тех файлах где будем работать с базой.

<?
require("ваш_путь/setup.php");
require("ваш_путь/config.php");
?>

и в конечном итоге получаем красивый и вполне безопастный код.

$dbc=db_connect();
$query = "SELECT .................";
$result = mysql_query($query,$dbc);

28.2 Как защитить /etc/passwd от просмотра?

В конфигурационном файле сервера Apache, в контексте соответствующей
директивы <Directory> указать(или в .htaccess):

php_admin_value open_basedir /home/null/www/htdocs
php_admin_value doc_root /home/null/www/htdocs

28.3 инклуды (.inc)

часто приходится хранить всякие везде-используемые данные/функции в отдельных файлах, и потом подключать,
используя include[_once]/require[_once].

но эти файлы обычно не парсятся сервером, т.е. их можно смотреть через браузер, этого мы и хотим избежать.
давать таким файлам расширение .php не очень правильно, т.к. их можно вызвать через браузер, и,
хотя мы и не увидим содержимое, но, наверняка, у нас начнут вылазить какие-либо ошибки PHP,
т.к. код внутри файлов обычно расчитан на исполнеие в определенном окружении(наличие коннекта к базе/
чтение файлов/определенные значения констант/переменных).

есть 2 выхода по сути похожих
1. поместить все .inc файлы за пределами DOCUMENT_ROOT Apache
2. написать .htaccess чтобы запретить доступ ко всем файлам с определенными расширениями
Пример.
<FilesMatch "\.(inc|sql|...другие расширения...)$">
order deny,allow
# запретить доступ отовсюду
deny from all
#разрешить доступ с вашего ip(если он у вас, конечно, статический)
allow from <ваш ip>
</FilesMatch>


29. Шаблоны. (Easy,FastTemplate)

Section Content

29.1 Что такое шаблоны и зачем они нужны?

29.2 Как влияет использование шаблонов на скорость отклика сервера?


30. E-Shop (принцип построения, работа)

Section Content

31. DB: MySQL

Section Content

31.1 С чего начать?

Я думаю, сейчас самое время перейти от слов к делу - сделать первый небольшой скрипт. Возьмем для примера следующую задачу. Нужно сделать базу с книгами, которые появились или скоро появятся в продаже, и которые вызывают интерес.

Для этого нам понадобятся: база (таблицы сделаем в MySQL), форма ввода, процедура загрузки из текстового файла (на тот случай, если ранее список книг лежал в файле - у меня дело именно так и обстоит), страница для вывода с сортировкой по критериям и, как дополнительный прибамбас (его сделаем в самую последнюю очередь), загрузка новостей с сайтов издательств с занесением выбранных позиций в базу.

Цель проекта проста. Не упустить интересующее чтиво.

Структура таблиц будет такой. Таблица описания книг BOOKS:

id int(5) - уникальный id autoincrement primary key - сначала хотел сделать автора и название ключем, решил, что это будет неудобно, если решим добавлять ссылочные таблицы)
author char(60) - автор
namebook text(100) - название книги
series int(2) - id серии (если книга принадлежит серии) - для серий отдельная таблица
edition int(2) - издание
year int(4) - год издания
isbn char(20) - ISBN (интересно, 20 символов хватит?)
pages int(4) - объем книги
when_create int(2) - номер квартала (за точку отсчета возьмем I квартал 2000)
how int(4) - предположительная цена
status int(1) - id статуса: обязательно заказать, посмотреть подробнее и т.п.
Для начала хватит. Потом добавим серии книг, статусы, таблицу оглавлений и обложек (в blob-ах), комментарии к книгам и список интернет-магазинов, в которых книга была обнаружена.
Для создания таблицы нам понадобится создать базу данных в MySQL (назовем ее тоже BOOKS) и в ней уже саму таблицу. Но сначала об установке MySQL. Я опишу установку под WinNT (под *nix-ы его надо собирать - я пока это проделывать не пробовал).

Процедура эта довольно проста. Надо забрать дистрибутив с http://www.mysql.com, раскрыть zip, запустить setup.exe. После окончания установки в каталоге MySQL-я будет лежать файл my-example.cnf. Предполагается, что его надо будет скопировать в каталог c:\ под именем my.cnf. Я этого не делал. Вместо этого, следуя Readme-файлу, я запустил winmysqladmin.exe, выбрал закладку "my.ini Setup", указал директорию, в которой живут поддиректории MySQL-я (у меня это C:/usr/local/mysql), выбрал радиобаттон в секции "mysqld file" mysqld-nt (запуск MySQL-сервера как службы в NT) и нажал на "Save Modification". После чего в WINNT-каталоге обнаружил файл my.ini. Все. Осталось убедиться, что в списке служб появилась служба "mysql", и выставить ей атрибут запуска (руками/автоматом).

Итак, заходим в каталог (если вы, конечно, не внесли эту директорию в path-окружение) c:\mysql\bin (или туда, куды вы установили MySQL; далее будем полагать, что mysql установлен в c:\mysql) и запускаем mysqladmin с параметром (краткую справку по параметрам mysqladmin-а я приведу в следующем шаге).

    create <имя база>.
В нашем случае
    create books.
mysqladmin никакой мессагой нас не порадовал, но, зайдя в c:\mysql\data (там по умолчанию mysql хранит базы данных, если не задано противное в конфигурации сервера), можно с чувством глубокого удовлетворения обнаружить директорию books. Это и есть наша база. Правда, директория пуста - мы ведь не создали в базе еще ни одной таблицы. (Кстати, если вы решите удалить базу пудем удаления директории - лучше откажитесь от этой затеи. Mysql хранит у себя информацию о существующих базах. Для корректного удаления базы есть параметр у mysqladmin-а:
    drop <имя базы>.
Создаем таблицу. Можно зайти в mysql.exe и создать там, а можно скормить тектовый файл с командами для mysql-я на вход exe-шнику. (При заходе с локальной машины mysql считает, что пришел root со всеми полномочиями - о пользователях и полномочиях в mysql-е поговорим позднее).
Итак, либо, зайдя в mysql, введите нижеследующую последовательность команд, либо сохраните их в файле (например, books.sql) и скажите

    mysql < books.sql
А вот содержимое books.sql:
connect books;
create table books (
    id int(5) not null primary key auto_increment,
    author char(60),
    namebook varchar(100),
    series int(2),
    edition int(2),
    year int(4),
    isbn char(20),
    pages int(4),
    when_create int(2),
    how int(4),
    status int(1)
    );
Зайдя теперь в каталог c:\mysql\data\books, вы обнаружите целых три файла: books.frm (структура таблицы), books.myd (данные; сейчас он нулевой длины - insert-ов ведь не было!) и books.myi (данные о ключах).
На последок небольшое пояснение по первой строке (полю) в insert-е. По идее, параметр "not null" не нужен, раз "primary key" говорим. Но есть мнение, что лучше все же его указать (я не готов это утверждение как-либо комментировать). Auto_increment, соответственно, присваивает одноименный атрибут полю, позволяя при insert-е автоматически генерить цифру на единицу большую, чем в предыдущем insert-е.


31.2 Как вывести данные из таблицы?

Итак, база (и первая таблица в ней) созданы.

Напишем скрипт, который будет формировать html-страницу с содержимым таблицы. Но сначала таблицу надо заполнить содержимым. Так как форма ввода у нас еще не создана, то воспользуемся методом из предыдущего шага - создадим sql-запрос на добавление записи в таблицу и направим его (файл с запросом) на вход mysql.exe.

Вот этот скрипт:

connect books;
insert into books (
    id, author, namebook, series, edition, year, isbn,
    pages, when_create,    how, status)
    values (null, "Р. Яргер и др.",
    "MySQL и mSQL. Базы данных для небольших предприятий и Интернета",
    0, 0, 2000, "5-93286-010-3", 557, 3, 170, 0),
     (null, "Ларри УОЛЛ", "Программирование на Perl",
    0, 3, 2001, null, 1200, 5, null, 0);
Несколько замечаний по этому запросу. Во-первых, я не сказал "commit". В данном случае это не обязательно, т.к. commit произойдет по окончанию скрипта автоматически. Во-вторых, в качестве значения для ключевого поля id выбрано значение null, что заставляет mysql присвоить (в силу параметра для поля auto_increment) числовое значение, на единицу большее, чем максимальное из существующих значений для этого поля в таблице. В-третьих, некоторые поля мы "занулили" - потом заполним. И в-четвертых, этот запрос к sql-серверу отличается от стандарта! Дело в том, что (как я уже говорил) mysql имеет некоторые отличия от sql-стандарта. В частности, insert допускает такую сокращенную форму записи. По правилам я бы должен был бы вместо одного insert-а с перечисленными через запятую группами значений в values использовать два запроса. Но мы облегчили себе жизнь. Вообще-то это, на мой взгляд, не лучшая практика - использовать всякие "отклонения от нормы". По крайней мере страдает переносимость. Но нас сейчас эта тема вряд ли должна волновать.
Теперь напишем скрипт для нашей первой страницы. HTML-код пока использован по минимуму. Кстати, чуть не забыл. Если вы используете (готовитесь использовать ;) PHP3, то в php3.ini в виндючем каталоге раскомментируйте строчку

extension=php3_mysql.dll
Для PHP4 (его ini-файл кличут php.ini) ничего делать не надо, т.к. поддержка mysql в 4-й версии встроенная.

А теперь обещанный скрипт:
<html><body>
<table border=1>
<?php
$db_name="books";    //база данных
$table="books";        //таблица
$host="localhost";    //хост
$user="";        //логин (при коннекте к локальному хосту логин и пароль не нужен - нас итак пустят! ;)
$pass="";        //password
//законнектимся - получаем link-идентификатор или вывод номера и текста ошибки
//с последующим прерыванием работы скрипта (die())
$link=mysql_connect($host,$user,$pass) or die(mysql_errno($link).mysql_error($link));
//выбираем базу данных BOOKS, созданную нами ранее
$db=mysql_select_db($db_name,$link) or die(mysql_errno($link).mysql_error($link));
//выберем данные
$result=mysql_query("SELECT * FROM ".$table, $link) or die(mysql_errno($link).mysql_error($link));
//сформируем заголовок таблицы результатов выборки
$th=explode("#","ID#Автор#Название книги#Серия#Ред.#Год#ISBN#Стр.#Когда#Цена#Статус");
echo "<tr><th>",implode("</th><th>",$th),"</th></tr>";
//выведем результаты в HTML-документ
while($data=mysql_fetch_row($result)) {
    echo "<tr><td>", implode("</td><td>",$data), "</td></tr>";
}
//освободить выделенную под результат выборки память
mysql_free_result($result);
mysql_close($link);
?>
</table>
</body></html>
Некоторые комментарии (более подробно в следующих шагах).
Во-первых, даже в такой упрощенной форме код работы с mysql избыточен. Т.к. мы работает с одной базой, да еще и делаем единственный запрос, то вместо mysql_connect(), mysql_select_db() и mysql_query() достаточно было вызвать mysql_db_query(). Эта функция при необходимости выполнит коннекцию (в прочем, в этом она не одинока), выберет базу данных и выполнит запрос к базе.

Во-вторых, mysql_close() тоже необязательна, т.к. соединение с сервером будет автоматически закрыто при окончании скрипта.

В-третьих, и уж конечно же в данном случае во mysql_free_result() никакой необходимости. Освобождать память при единственном запросе да еще такого незначительного объема... Здесь эта функция вызвана скорее для демонстрации возможных операций с mysql на php, ну или, если хотите, для порядка. ;)

В-четвертых, функции implode() и explode() относятся к стринговым. Этой теме будет посвящен отдельный шаг (шаги). А пока: explode() создает массив из фрагментов строки, разбирая ее как строку с разделителем, указанном в первом параметре. Implode() делает обратную операцию. Эту пару я применил для удобства - по-моему это проще, чем набирать строку в виде "...текст</th><th>текст..." и уж тем более проще, чем делать кучу echo с текстами, обрамленными тегами <th>/</th>.

И в-пятых, сие чудо программистской мысли ;) выполняется как под 4-й версией php4, так и под 3-ей.

Далее в программе: подробное описание функций работы с mysql, форма для ввода записей, чтение (импорт) данных из файла и запись (экспорт) в файл, index.php3.

31.3 Какие типы данных поддерживает Mysql?

Я не буду описывать подробно все изобилие типов MySQL. Я уверен, что это лишнее. Дело в том, что в mysql-е числовые и текстовые группы типов очень многочисленны. Отличаются типы в этих группах размером в байтах и возможными модификаторами. Подробности можно посмотреть в мануале в директории Docs каталога с mysql-ем в разделе "7.3 Column types". Там и английский знать особо не нужно - смотрите на название и цифры длины! ;)

Здесь я сделаю обзор самих групп типов данных - для быстрого введение.

MySQL поддерживает следующие типы/группы типов данных:

Числовые. Возможные модификаторы: UNSIGNED для объявления беззнаковости, ZEROFILL для заполнения лидирующих пробелов нулями (имеется в виду внешний вид при выводе). Могут быть созданы как целые (TINYINT, SMALLINT, INT, BIGINT и пр.), так и числа с плавающей точкой (FLOAT, DOUBLE, REAL и пр.).
Строковые. Возможные модификаторы: BINARY для объявления поля как бинарного (любые коды хранимых символов), NATIONAL - модификатор по умолчанию, - использование набора символов для сортировки, сравнения и пр. Занятный модификатор. Отвечает за конструкцию SET-группы: SET CHARACTER SET character_set_name | DEFAULT, где character_set_name может принимать значение cp1251_koi8.
Однако эти установки выставлены по умолчанию. Выходит, без модификатора результат тот же, что и с ним. Я так понял, что эти фишки для будущего использования. Модификатор для типа CHAR VARYING создает строковое поле переменной длины.

BLOB-поля - поля для хранения двоичных данных.
Типы данных, не попавшие в предыдущие три группы:
TIMESTAMP - поле хранит дату и время последнего изменения записи. Это значит, что, добавив в таблицу поле типа TIMESTAMP (например, воспользовавшись конструкцией ALTER TABLE table_name ADD COLUMN column_name TIMESTAMP), Вы, не производя никаких изменений поля типа TIMESTAMP, будете в нем иметь время последней операции с записью, влияющей на содержимое строки таблицы.
DATE, TIME, DATETIME - поля хранения даты, времени, и того, и другого. Тут, я думаю все ясно.
YEAR - поле, добавленное в версии 3.22, - для хранения года в интервале с 1901 по 2155.
ENUM - поле, хранящее одно из значений, указанных в списке при создании (модификации структуры) таблицы, например, ALTER TABLE tab_name ADD COLUMN col_enum ENUM('Ага', 'Угу', 'Ну его нафиг'). Теперь поместить в поле col_enum одно из перечисленных значений можно так:
INSERT INTO tab_name SET col_enum='Ага'
или
UPDATE tab_name SET col_enum=3.
В последнем случае в col_enum будет значение 'Ну его нафиг'. Присвоение полю значения не из списка (например, col_enum=7 или col_enum='format c:') запишет в поле пустую строку (даже не 'NULL').
тип SET в отличии от типа ENUM предназначен для хранения списка значений, например,
ALTER TABLE tab_name ADD COLUMN col_set SET ('один','два','три','четыре')
Теперь изменим значение поля:
UPDATE tab_name SET col_set='один' WHERE поле=значение
После такого запроса col_set будет содержать значение 'один'.
UPDATE tab_name SET col_set=15
Здесь col_set содержит значение 'один,два,три,четыре'. Да, именно строку с set-значениями, разделенными запятыми. Цифра 15 - это двоичное 1111. Каждый бит отвечает за свое значение в списке. Например: 1 - 'del', 10 - 'file1.txt', 11 - 'del,file1.txt' и т.д. Как и в случае с ENUM установка недопустимого значения записывает в поле пустую строку.

31.4 Как разбивать запрос на страницы (постраничный вывод данных)?

Что такое разбивка на страницы? Самый простой пример - поисковые машины.
Вы даете команду на поиск в ответ на что сервер выдает
тысячи ссылок (и прочая информация типа названия страницы, даты, и пр.).
Но находится данная информация не на одной странице.
Она разбита на части. В этом примере вы научитеть разбивать
результат поиска по базе данных на куски, чтобы организировать
постарничный вывод.

Cоздадим файл default.phtml, который содержит базовые фукнции. Вам надо
подправить параметры (host/user/pass/base)
<?

// Глобальная переменная. Например, нужна в функции коннекта.
$sock=false;


// новые функции
function sql($a) { return mysql_query($a); }
function sqlrows($a) { return @mysql_num_rows($a); }
function sqlval($a,$b,$c) { return @mysql_result(mysql_query($a),$b,$c); }
function sqlget($a) { return @mysql_fetch_array($a); }
function sqlline($a) { return sqlget(sql($a)); }
function sqllast() { return mysql_insert_id(); }


// коннект к серверу
function connect() {
global $sock;

$host="*****";
$user="*****";
$base="*****";
$pass="*****";

$sock=@mysql_connect($host,$user,$pass);
if ( ! $sock || ! @mysql_select_db($base,$sock))
die("Сервер временно не работает");

unset($host);
unset($user);
unset($base);
unset($pass);

}

// замена die()
function xdie($zapros="", $info="") {
die("</table></table></table></table><hr><h3>************ $info ***********<br><br>
SQL ERROR..... N".mysql_errno().": ".mysql_error()."</h3><pre>$zapros</pre><hr>");
}


?>

=== 2 ===

данный файл (create.phtml) создаст таблицу limit_test и забьет в нее 500 строк
вида из разных строк.
<?

include("./default.phtml");

connect();

// удаляем таблицу (на всякий случай)
sql("DROP TABLE limit_test");
// создаем
if (!sql("CREATE TABLE limit_test (id int, s char(100))"))
xdie("","Таблица не создана");

srand(time());

// создаем запрос вида << ... VALUES (x,"xx"), (y,"yy"), ... (z,"zz") >>
$s="INSERT INTO limit_test VALUES ";

for ($i=0; $i<500; $i++) {

$s.="($i,\"";
$x=rand(1,100);
for ($j=0; $j<$x; $j++) $s.=chr(rand(ord('a'),ord('z')));
$s.="\")";
if ($i+1<500) $s.=",";

}

// выполняем запрос, чтобы наполнить таблицу данными
if (!sql($s)) xdie($s,"Таблица не заполнена");

?>

Done.

=== 3===

Собственно, сам файл (search.phtml), который выводит на экран форму для поиска и
выводит найденные результаты по ?? штук на страницу.
<body bgcolor=black text=white link=#9999cc vlink=#cc9999><font face=arial>
<?

include("./default.phtml");

if (!isset($z)) $z="";
if (isset($all)) $all=intval($all);
if (isset($start)) $start=intval($start);
if (isset($len)) $len=intval($len);
else $len=10;

echo "<form action="http://phpclub.chat.ru/mysql/%24PHP_SELF" method=get>
<input type=hidden name=z value=search>
Что ищем:
<input type=text name=s value='$s'>
Строк:
<input type=text name=len value='$len' size=5>
&nbsp; <input type=submit value=' search '><br><br>
Спец. символы:
<font color=#ff6666><b><big>_</big></b></font> - заменяет 1 любую букву,
<font color=#ff6666><b><big>%</big></b></font> - заменяет любую последовательность букв.
Поиск '<b>%</b>' - найдет все строки, поиск '<b>_</b>' - только строки,
состоящие из 1 символа. Если поискать 'a', то, скорее всего, ничего
не будет найдено, однако строки '%a%' точно найдутся.<br>
</form>";

switch ($z) {

case "search":

connect();

$query="SELECT s FROM limit_test WHERE s LIKE '$s'";

if (!isset($start)) {

if (!( $res=sql($query) )) xdie($query,"ошибка");
$start=0;
$all=sqlrows($res);

} else {

$query.=" LIMIT $start,$len";
if (!( $res=sql($query) )) xdie($query,"ошибка");

}

echo "Запрос: <font color=#00ff00>$query</font><br><br>";

for ($j=1; $j<=$len && $tmp=sqlget($res); $j++) {
echo ($start+$j).". $tmp[s]<br>";
$stop--;
}

echo "<br>";
for ($i=1; $i<=floor($all/$len); $i++)
echo "<a href="../../tppmsgs/msgs0.htm#123" tppabs="http://phpclub.chat.ru/mysql/%24PHP_SELF?z=search&all=$all&len=$len&"."
"start=".(($i-1)*$len)."&s=".urlencode($s).">$i</a> ";

break;
}


?>





32. DB: Postgres

Section Content

32.1 Как подключить PostgreSQL к PHP (a.k.a undefined function pg_connect())?

Сборка из исходников: при настройке исходников (./configure) надо обязательно указать ключ
--with-pgsql=/path/to/pgsql/install


Установка из RPM: надо установить пакет
php-pgsql.[version].rpm

32.2 Как сделать, чтобы PostgreSQL поддерживал русский в кодировке [нужное вписать]?

По порядку:

1. PostgreSQL должен быть собран с ключами --enable-locale --enable-multibyte. RPM'ы, как правило, собираются с этими ключами, если вы собираете из исходников — не забудьте их указать!

2. У пользователя, от лица которого работает сервер (обычно postgres) должна быть установлена нужная локаль. Этого можно добиться, например, добавив в его файл .bash_profile строки:

LANG=ru_RU.KOI8-R
export LANG

Если нужной локали (например с кодировкой CP1251) в системе нет, то перед этим надо проделать следующее:

$ localedef -c -i ru_RU -f CP1251 ru_RU.CP1251

3. После этого надо проинициализировать директорию, в которой будут находиться базы данных, указав кодировку по умолчанию (можно, впрочем и не указывать):

$ initdb -E KOI8

или, для любителей длинных ключей

$ initdb --encoding=KOI8

Учтите: начиная с версии 7.1 порядок сортировки строк и разница между заглавными/строчными буквами задаётся именно при этой инициализации в соответствии с установленной локалью, потом их изменить нельзя. До версии 7.1 эти значения определялись локалью при запуске postmaster'а, что могло привести к порче индексов по текстовым полям.

4. Кодировку также можно указывать при создании отдельных баз:

$ createdb -E win mustdie

5. Если все шаги проделаны верно, то сортировка, функции upper()/lower(), операторы ILIKE и ~* должны работать правильно. Если не работает хотя бы одна из этих функций — проверьте настройки.

32.3 А есть ли аналог phpMyAdmin для PostgreSQL?

Есть. Называется (сюрприз-сюрприз) phpPgAdmin, смотреть здесь: http://www.greatbridge.org/project/phppgadmin/projdisplay.php

32.4 Миграция с MySQL: как сделать поле auto_increment?

Если неохота разбираться в тонкостях:

CREATE TABLE foo (
id SERIAL,
...
);

и всё заработает.

Если есть желание разобраться:
Для генерации «суррогатных» первичных ключей в PostgreSQL используются «последовательности» (SEQUENCE). Вышеприведённый пример на самом деле раскрывается в такую конструкцию:

CREATE SEQUENCE foo_id_seq;
CREATE TABLE foo (
id integer DEFAULT nextval('foo_id_seq'),
...
);
CREATE UNIQUE INDEX foo_id_key ON foo (id);

Если делать ту же работу «вручную», то нагляднее всего (IMHO!) получается так:
CREATE SEQUENCE foo_seq;
CREATE TABLE foo (
id integer NOT NULL DEFAULT nextval('foo_seq'),
...,
PRIMARY KEY (id)
);

Если нужно (как чаще всего и бывает), чтобы поле заполнялось автоматически, не надо указывать его в команде INSERT вообще. При попытке вставить туда значение NULL или 0 возникнет ошибка.

Следует отметить: последовательность совершенно не зависит от таблицы, при большом желании можно использовать одну и ту же последовательность для генерации ключей в разных таблицах. Вообще, возможности последовательностей в PostgreSQL значительно шире, чем auto_increment полей в MySQL. Как обычно, читайте документацию. :]

32.5 Миграция с MySQL: аналог mysql_insert_id()?

Если для генерации ID используются SEQUENCE'ы (см. предыдущий вопрос), то вот такой запрос:

SELECT currval('sequence_name');

выдаст последнее значение, выбранное из последовательности sequence_name функцией nextval() в текущем соединении с базой. Подчёркиваю: в разных, пусть даже одновременно работающих, скриптах эта функция будет возвращать разные значения.
Если же в текущем соединении функция nextval('sequence_name') не выполнялась, то currval('sequence_name') вернёт ошибку.


Также можно использовать функцию pg_getlastoid(), особенно если нужно получить не ID последней записи, а какие-то другие поля.
Она возвращает значение oid — неявного системного поля — последней вставленной записи.
Выбрать собственно ID записи можно следующим запросом:

SELECT id FROM foo WHERE oid={$oid};

где $oid — значение, полученное от pg_getlastoid().


33. DB: Oracle

Section Content

34. DB: MSSQL

Section Content

34.1 При обращении к серверу через php_mssql.dll вместо русских букв выдаются букашки. Как можно их декодировать?

Перед INSERT запросoм надо выполнить:
convert_cyr_string($query,"w","a");

После запроса на выборку SELECT выполнить преобразование:
convert_cyr_string($res['value_string'],"a","w");

Решение от
Vitali Nasonov
nasonov@carb.siobc.ras.ru

в настройках MSSQL: (на примере MSSQL7/NT4):

Start -> Program -> MS SQL Server 7.0 -> Client Network Utility ->
-> DB Library Options -> Automatic ANSI to OEM Conversion (убрать
галочку)



35. DB: Interbase

Section Content

36. DB: Sybase

Section Content

37. XML & XSLT

Section Content

37.1 XML/XSLT в PHP4: как и зачем?

Установка

Для того, чтобы иметь возможность писать документы в XML с последующей трансформацией в HTML через XSLT вам нужно иметь PHP4 сконфигуренный с поддержкой:

XML (--with-expat)
XSLT (--with-sablot=/usr/local)

Как использовать

Для начала надо ознакомиться с докой PHP по использованию XSLT а также XSLT specification и XPath language.

Также вам понадобиться использовать output буфферы чтобы перенаправить сгенеренный PHP текст в XSLT процессор.

После этого вы можете написать простой скрипт:

<?
/* начинаем буффер */
ob_start()?>
<xml>
<title>Welcome to the world!</title>
<author>
    <name>Ruslan</name>
    <email>contact@ruslan.org</email>
</author>
<content>
Hello world form <?echo $PHP_SELF?>!
<p/>
<?/* любой PHP код выводящий <u>правильный</u> XML! */?>
Привет по русски!
<p/>
Для того что-бы использовать русский язык нужно перед
обработкой преобразовать в UTF8 а после обработки обратно.
</content>
</xml>
<?
/* берем из буффера */
$text = ob_get_contents();
ob_end_clean();
/* читаем XSL stylesheet */
$xsl = join("", file("example.xsl"));
/* обрабатываем */
xslt_process(utf8_encode($xsl), utf8_encode($text), $result);
/* выводим на экран результат */
echo utf8_decode($result);
//echo "<pre>" . htmlspecialchars(utf8_encode($text)) . "</pre>";
?>


Используется следующий шаблон example.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
indent="yes"
encoding="utf-8"
/>

<xsl:template match="xml">
<html>
    <xsl:apply-templates/>
</html>
</xsl:template>

<xsl:template match="title">
    <font size="+1"><xsl:apply-templates/></font>
</xsl:template>

<xsl:template match="author">
    by <a href="mailto:{email}">
        <xsl:value-of select="name"/>
    </a>
</xsl:template>

<xsl:template match="content">
    <blockquote>
        <xsl:apply-templates/>
    </blockquote>
</xsl:template>

<xsl:template match="p">
    <p/>
</xsl:template>

</xsl:stylesheet>

После работы которого на экран будет выводится следующее:

<?xml version="1.0" encoding="utf-8"?><html>
<font size="+1">Welcome to the world!</font>

    by <a href="mailto:contact@ruslan.org">Ruslan</a>
<blockquote>
Hello world form /ruslan/xsltlib/example.php!
<p/>
Привет по русски!
<p/>
Для того что-бы использовать русский язык нужно перед
обработкой преобразовать в UTF8 а после обработки обратно.
</blockquote>
</html>

Зачем?

Это очень удобно, php генерит контент а xsl шаблон создает HTML страничку(пожно WAP, TXT, etc). Вам не надо думать о том как это выглядит, только о структуре данных, представленных в XML.

Есть одна проблема: XSLT расширение PHP пока немножко глючное(или это у меня :-)).

p.s. Эта статья вместе с примером доступна по адресу: http://www.ruslan.org/dev/xslt-example.zip

37.2 Поддержка кодировок в XSLT парсере Sablotron

В документе надо указать
<?xml version="1.0" encoding="input-encoding"?>
где
input-encoding ::= CP1251 | KOI8-R

В stylesheet`е
<xsl:output method="xml|html|text" encoding="output-encoding">

output-encoding ::= CP1251 | KOI8-R

Перекодирование производится с помощью библиотеки iconv
(iconv --list)

Только для Linux/Unix платформ.
Взято из
http://www.gingerall.com/charlie-bin/get/webGA/act/sablot_faq.act

Added by Slach < slach@chel.ru >
Также существует Path для Sablot 0.51 который можно применять и для последующих версий (0.52 например).
Лежит по адресу
http://btp1da.phy.uni-bayreuth.de/ftp/pub/FreeBSD/ports/textproc/sablotron/files/rus-patch

Для win32 откомпилированный Sablot 0.51 с поддержкой win1251 лежит по адресу
http://quake.ems.ru/files/sablot.win1251.zip

Added by Slach < slach@chel.ru >
============== RU.XML ================
многие спрашивают, как запустить sablotron на win32
с поддержкой русских кодировок.
осмелюсь ответ дать в эху. бинарь под win32 на gingerall скомпилен без iconv. так что... 0. будем считать, что лежать файлы будут:
c:/usr/local/bin- бинари
c:/usr/local/include- include-файлы
c:/usr/local/lib- библиотеки в PATH должен быть прописан c:/usr/local/bin сложный путь
--------------- 1. скачиваем expat-
http://prdownloads.sourceforge.net/expat/expat-1.95.1.tar.gz
(в бинаре нет либ - так что компилим сами)
распаковываем, компилим:
lib/expat.dsp
expat.h ->/usr/local/include/expat.h
expat_1_95_1.dll->/usr/local/bin/expat.dll 3. скачиваем iconv -
ftp://ftp.ilog.fr/pub/Users/haible/gnu/libiconv-1.6.1.tar.gz
распаковываем, компилируем (нужен MSVC):
nmake -f Makefile.msvc DLL=1 MFLAGS=-MD include/iconv.h ->/usr/local/include/iconv.h
lib/iconv.lib->/usr/local/lib/iconv.lib
lib/iconv.dll->/usr/local/bin/iconv.dll 4. скачиваем sablotron - (бинарь скомпилен без iconv'а, так что сами
делаем)
http://www.gingerall.com/perl/rd?url=sablot/Sablot-0.52.tar.gz
распаковываем, компилируем (нужен MSVC): простой путь
---------------
1. скачиваем expat-
http://prdownloads.sourceforge.net/expat/expat_win32bin_1_95_1.zip
ставим в /usr/local
expat_1_95_1.dll->c:/usr/local/bin/expat_1_95_1.dll 2. скачиваем бинарь iconv от меня
http://protey.ru/xml/libiconv-1.6.1-win32bin.rar
ставим в /usr/local
iconv.dll->c:/usr/local/bin/iconv.dll 3. скачиваем бинарь sablotron от меня
http://protey.ru/xml/Sablot-0.52-win32bin.rar
ставим в /usr/local
sabcmd.exe->c:/usr/local/bin/sabcmd.exe
sablot.dll->c:/usr/local/bin/sablot.dll тест
---------------
incl.xsl:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text"
encoding="koi8-r"
/>
<xsl:template name="alone">
<xsl:text>&#010;</xsl:text>
<xsl:text>OK7</xsl:text>
<xsl:value-of select="data/item"/>
</xsl:template> </xsl:stylesheet> incl.xml:
<?xml version="1.0" encoding="cp1251"?>
<item>OK4-тест</item> sabcmd.exe incl.xsl incl.xml incl.out в incl.out видим в koi8:
OK4-тест вот и все :)

37.3 Как подружить php4.0.6 и libxslt?

Прежде всего объявляется вечная благодарность su1d'у ;) за терпение и усидчивость... а также за то, что скомпилил php_gxslt под win32
1) качаем libxslt
http://www.fh-frankfurt.de/~igor/projects/libxml/data/libxml2-2.4.10.win32.zip

http://www.fh-frankfurt.de/~igor/projects/libxml/data/libxslt-1.0.7.win32.zip

2) качаем iconv
http://www.fh-frankfurt.de/~igor/projects/libxml/data/iconv-1.7.win32.zip

3) кладем libxslt.dll libexslt.dll libxml2.dll iconv.dll в c:\WinNT\system32\ причем libxml2.dll там наверняка уже лежит, потому что поставляется вместе с php4.0.6... но там старая версия поэтому надо затирать
4) туда же кладем xsltproc.exe (это аналог sabcmd.exe)
5) идем сюда http://www.e-taller.net/dev/gxslt/
и качаем zip файлик с extention
6) кладем php_gxslt.dll в c:/usr/local/php/extentions/
Тестовые файлы для проверки работоспособности...
====test.xml====
<?xml version="1.0" encoding="windows-1251"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<cookbook>
<recipe>
<name>Pasta Carbonara</name>
<difficulty>Easy</difficulty>
<time>25 minutes</time>
<rating>*****</rating>
<chef>Chef Michele</chef>
<comments>This delicious Italian dish consists of a blend
of pasta, bacon and eggs. Eat it morning, noon or
night! Єшяр ЄхёЄ ш тёх Єръюх... шэЄхЁхёэю </comments>
</recipe>
<recipe>
<name>La Bistecca</name>
<difficulty>Difficult</difficulty>
<time>35 minutes</time>
<rating>*****</rating>
<chef>Chef Nino</chef>
<comments>La Bistecca, Italian for 'steak', grilled tender
in the summertime is my favorite dish!</comments>
</recipe>
<recipe>
<name>Pollo fritto</name>
<difficulty>Difficult</difficulty>
<time>45 minutes</time>
<rating>*****</rating>
<chef>Chef Rita</chef>
<comments>Nothing says Italian like fried
chicken!</comments>
</recipe>
</cookbook>
====test.xml====
====test.xsl====
<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="windows-1251" method="html" />
<xsl:template match="/cookbook">
<head>
<title>What's Cooking at WebReview</title>
</head>
<body bgcolor="white" text="#000000" link="#ff8000"
vlink="#000000" alink="#ff0000">
<center>
<table bgcolor="white" border="0" cellpadding="0" cellspacing="0">
<xsl:call-template name="recipes"/>
</table>
</center>
</body>
</xsl:template>
<xsl:template name="recipes">
<xsl:for-each select="recipe">
<tr>
<td width="60%">
<font size="4"><xsl:value-of select="name"/>
</font>
<br/>
Rating: <xsl:value-of select="rating"/>
<br/>
Preparation time: <xsl:value-of select="time"/>
<br/>
Submitted By: <xsl:value-of select="chef"/>
<br/>
Level: <xsl:value-of select="difficulty"/>
<br/>
<xsl:value-of select="comments"/><br/>
<hr/>
</td>
</tr>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
====test.xsl====
====libxslt.php====
<?php
$xml_file = "test.xml";
$xsl_file = "test.xsl";
// Open each file and assign it to a filehandle.
$xml_handle = fopen($xml_file, "r") or die("Can't open XML file!");
$xsl_handle = fopen($xsl_file, "r") or die("Can't open XSL file!");
// Read in the file contents.
$xml_content = fread($xml_handle, filesize($xml_file));
$xsl_content = fread($xsl_handle, filesize($xsl_file));
$xsl_tfmtion= gxslt_process($xml_content, $xsl_content,'CP1251');
echo $xsl_tfmtion;
$fl=fopen('text.html','w');
fwrite($fl,$xsl_tfmtion);
fclose($fl);
// Free up the processor resources.
?>
====libxslt.php====
Всего наилучшего,
.... Slach


38. DEMO ZONE !!!

Section Content

38.1 Что это ???

Пишите сюда! Тестируйте куски скриптов...
Балуйтесь короче ... :))
Заоодно проверьте защиту..

38.2 Тест на ответ!

38.3 Здравствуйте! Выпущена новая версия PHP фронтэнда для популярной поисковой системы mnoGoSearch - 3.1.3.3 Релиз включает в себя различные дополнения и исправления, которые перечислены в changelog на сайте mnoGoSearch http://mnogosearch.org

38.4 Ну-с, попробуем..

И что получаем?


39. Буферизация вывода (GZIP & ...)

Section Content

39.1 Как на лету заархивировать файл в переменную ?

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

Для этого можно использовать недокументированную функцию shell_exec(). Она работает в версиях PHP, начиная с четвёртой. Её описание отсутствует в документации, но кое-что можно прочитать в комментариях к функции exec()(http://www.php.net/manual/nl/function.exec.php).

Пример использования:

<?
$file = "file_to_zip.ext";
$zipfile=shell_exec("zip - ".$file);
?>

В результате выполнения этого кода, файл file_to_zip.ext будет заархивирован архиватором PKZIP и считан в переменную $zipfile.

Чем хорош такой способ ? А тем, что не надо создавать временных файлов на диске. Вы получаете готовый архивированный контент, который можно запихнуть в тело письма ввиде аттача :)

Если Вы, как и я, планируете использовать PKZIP, то он должен быть установлен на сервере. Скачать UNIX-овую инсталляцию можно отсюда - http://www.pkware.com/shareware/pkzu251.html.

Ну и естественно очень советую выполнить на сервере man zip - все ключи в мане расписаны очень подробно :)


40. Отлов ошибок

Section Content

40.1 Parse-ошибки

Ошибки данного типа говорят о том, что автор скрипта, вероятнее всего, где-то опечатался. В общем виде выглядят примерно так:
Parse error: parse error *описание ошибки* in *локальный путь до скрипта с ошибкой* on line *номер строки с ошибкой*
Возможен и сокращённый вариант
Parse error: parse error in *локальный путь до скрипта с ошибкой* on line *номер строки с ошибкой*
Основные проблемы при устранении таких ошибок сводятся к двум:
1) Найти строку, на которую указывает интерпретатор (для пользователей Блокнота, или любого редактора, который при автопереносе заменяет настоящий номер строки)
2) Найти строку, в которой РЕАЛЬНО произошла ошибка. Обычно это либо заявленная в сообщении строка, либо одна из строк лежащих выше. Например следующий код:

echo "Привет !"

// В РНР оказывается есть коментарии !
// Ну нифига себе !

echo "Пока !";

Выдаст ошибку: Parse error: parse error, expecting `','' or `';'' in * локальный путь * on line 6, хотя реально ошибка допущена в первой же строчке ! (пропущена ; )

Ещё хуже дело обстоит с пропуском фигурных скобок.
Дело в том, что с точки зрения PHP запись

for ($i==0; $i<10; $i++)
echo "I=";
КОД
echo $i;
}

Содержит ошибку в 5 строке, а именно - лишнюю закрывающую скобку. Для интерпретатора код звучит примерно так:
1) Десять раз печатаем echo "I=";
2) Выполняем КОД
2) Печатаем echo $i;
3) А этто ещё что за } ?!
А ведь КОД может иметь не один десяток строк...

И совсем отдельная песня - кавычки. Во первых - кавычку можно пропустить:
<? echo "Переменные:;
echo $a;
echo $b;
// Ну нифига себе !
// А код может быть длинный !
echo $c;
echo $d;
echo "Пока !";
?>
Скрипт вызовет ошибку только в восьмой строке, хотя пропустили кавычку вы в первой.

Во-вторых кавычки можно перепутать, поскольку их в РНР два вида - " и ' :
<? echo "Переменные:';
echo $a;
echo $b;
// Ну нифига себе !
// А код может быть длинный !
echo $c;
echo $d;
echo "Пока !";
?>
Скрипт опять вызовет ошибку только в восьмой строке, хотя вы и закрыли кавычку - правда не ту, что открыли.
Ну и наконец, можно напечатать что-то вроде:

echo "<table border="0" width="780" align="center">";
и головная боль вам обеспечена.

А правильно так:
1. echo '<table border="0" width="780" align="center">';
Или так
2. echo "<table border=\"0\" width=\"780\" align=\"center\">";

Вот вроде и всё.
Напоследок несколько советов:
1) Используйте редакторы с подсветкой - незакрытые кавычки они вам продемонстрируют.
2) Все циклы, операторы выбора и т.п. оформляйте "лесенкой",
это позволит быстро найти пропущенную скобку.
3) Будьте бдительны :)

40.2 Как сделать собственный обработчик ошибок?

@ - атавизм.

Для отладки действительно лучше использовать error_reporting и перехватывать стандартный обработчик ошибок php.

Пример - кусок из моей бибилотеки.

if (DEBUG_MODE)
{
//All messages printed into browser window
// error_reporting(E_ALL & ~E_NOTICE);
error_reporting(E_ALL);
}
else
{
error_reporting(0);
include_once 'classes/bavlog.php';
set_error_handler(bavErrorHandler);
/*!
override PHP's main error handler function
this should NOT be called directly
*/
function nmErrorHandler($errno, $errmsg, $errfile, $errline, $vars)
{
...
... some analizer of error
}

}

А собственный вывод сообщений об ошибках и отладочной информации
сделать не echo, print() а через trigger_error().

Подробности об использовании собственного обработчика есть в документации.

40.3 Как подавить сообщения при ошибках?

Указание @ перед функцией блокирует вывод сообщения об ошибке

Если track_errors включен то последнее сообщение об ошибке сохраняется в
глобальной переменной $php_errormsg


41. Пасхальные яйца в PHP

Section Content

41.1 Есть ли в PHP секреты заложенные разработчиками?

Если написать в любом файле php:
(test.php3 заменить на свой)

<HR>
<img src="/test.php3?=PHPE9568F35-D428-11d2-A769-00AA001ACF42">
<HR>
<img src="/test.php3?=PHPE9568F34-D428-11d2-A769-00AA001ACF42">
<HR>
<img src="/test.php3?=PHPE9568F36-D428-11d2-A769-00AA001ACF42">
Получатся три картинки, самая прикольная из них это последняя, человек с карандашами в зубах :) наверное это один из авторов php :)