Статьи http://janicky.com Fri, 22 Sep 2017 07:58:15 +0000 ru-ru Установка Apache, PHP, Perl, MySQL Часть 2 http://janicky.com/stati/ustanovka-apache-php-perl-mysql_2 http://janicky.com/stati/ustanovka-apache-php-perl-mysql_2

Устанавливаем сервер базы данных MySQL

MySQL - наряду с Apache и php является одной из популярной платформ для создания веб сайтов, высокопроизводительная, бесплатное программное обеспечение, имея при этом преимущества и удобство по сравнению с её платными аналогами.

Установка MySQL проходит довольно просто. В папке C:\server создаём папку mysql, в которой мы будем устанавливать MySQL. Теперь она выглядит так, как показано на рисунке 1.

установка MySQL

Рис.1 Установка сервера базы данных MySQL

Для установки вам потребуется дистрибутив, который вы можете найти на офоициальном сайте разработчика mysql.com или скачать по ссылке mysql-5.5.23-winx64.msi После того, как вы скачали диструбтив, запустите установщик mysql-5.5.23-winx64.msi (расширение .msi будет скрыто).

установка MySQL

Рис.2 Установка сервер базы данных MySQL

Результатом будет окно с лицензионным соглашением, после принятия которого, следует перейти к следующему окну.

установка MySQL

Рис.3 Установка и настройка сервер базы данных MySQL

В новом окне, вам предлагается выбирать одно из трех вариантов установки установки: Typical(Обычная), Cusum (Выборочная), позволяющий выбрать все компоненты сервера вручную и Complete (Полная)

установка MySQL

Рис.4 Установка сервер базы данных MySQL

Выбираем на кнопку "Custom". B новом окне кликаем на кнопку “Browse” и вместо папки C:\Program Files\MySQL\MySQL Server 5.5\ выбираем папку C:\server\mysql

установка MySQL

Рис.5 Установка сервер базы данных MySQL

Кликаем “Next“ и выбираем папку, куда устанавливать MySQL

установка MySQL

Рис.6 Установка сервер базы данных MySQL

Кликаем на кнопку "Install", чтобы начать процесс установки.

установка MySQL

Рис.7 Установка сервер базы данных MySQL

Выбираем “Launch the MySQl Instance Configuration Wizard”, чтобы выполнить настройку сервера базы данных MySQL

установка MySQL

Рис.8 Установка сервер базы данных MySQL

После завершения установки MySQL на ваш компютер, запускается окно MySQL Server Instance Configuration Wizard установка MySQL

Рис.10 Настройка сервера базы данных MySQL

В этом окне вам предлагают выбрать два варианта настройки конфигурации: детализированная настройка (Detailed Configuration) и стандартная настройка (Standard Configuration) Выбираем детализированную настройку настройка MySQL

Выбираем сценарий установки: Developer Machine - для установки на домашний компьютер (по-умолчанию), Server Machine - для установки на сервер, Dedicated MySQL Server Machine - для установки на сервер полностью выделенный под MySQL. Эти опции влияют в первую очередь на объем потребляемой MySQL памяти.

настройка MySQL

А тут нужно выбрать тип базы данных из 3х опций: Multifunctional Database (будет установлена поддержка БД обоих типов), Transactional Database Only (будет установлена поддержка только InnoDB) и Non-Transactional database Only (будет установлена поддержка только MyISAM). Выбираем первый вариант и продолжаем настройку.

Рис.12 Настройка сервера базы данных MySQL

настройка MySQL

Рис.13 Настройка сервера базы данных MySQL

Если на предыдущем этапе вы выбрали поддержку InnoDB, здесь можно настроить расположение файлов данных InnoDB.

настройка MySQL

Поддержка одновременных соединений: Decision Support (до 20 одновременных соединений), Online Transaction Processing (до 500 соединений) и Manual Setting (ручная установка количества соединений).

Рис.14 Настройка сервера базы данных MySQL

настройка MySQL

Рис.15 Настройка сервера базы данных MySQL

В этом окне нужно выбрать порт и опции работы с сетью. Отмечаем опции «Enable TCP/IP Networking» и «Enable Strict Mode», порт оставляем без изменений и идём дальше.

настройка MySQL

Рис.16 Настройка сервера базы данных MySQL

настройка MySQL

Выбираем кодировку по умолчанию, рекомендую установить - utf-8;

настройка MySQL

Рис.17 Настройка сервера базы данных MySQL

Если вы хотите, чтобы MySQL запускалась как служба Windows каждый раз автоматически, выберите опцию «Install as Windows Service» (запускать как службу Windows).

настройка MySQL

Рис.18 Настройка сервера базы данных MySQL

Завершающий этап настройки, пароля администратора (root). Если не хотите устанавливать пароль, оставте эти поля пустыми.

настройка MySQL

Рис.19 Настройка сервера базы данных MySQL

Как только установка завершится, сервер MySQL запустится автоматически. Теперь необходимо убедиться в работоспособности сервера MySQL. Для этого следует открыть окно для работы с командной строкой, выбрав в системном меню Пуск -> Программы -> MySQL -> MySQL Server 5.5 -> MySQL Command Line Client.

Введите пароль. Сервер покажет текущую версию сервера.

настройка MySQL

Рис.22 Настройка сервера базы данных MySQL

Если сервер базы данных MySQL запушен, вы должны увидеть это окно, как на рисунке 23.

настройка MySQL

Рис.23 Настройка сервера базы данных MySQL

Установка почтового сервера

Для организации сервера электронной почты по протоколам SMTP и POP3 была выбрана программа Courier Mail Server. Courier Mail Server - это сервер электронной почты, работающий под ОС Windows. Courier Mail Server довольно проста в установке и распространяется бесплатно. Подробную информацию и последнюю версию программы вы можете скачать на сайте разработчика courierms.ru/

Скачивам Courier Mail Server courierms302_setup.exe. В папке C:\server создаём папку mail-server. Теперь ваша папка C:\server выгледет так, как показана на рисунке 1.

Установка почтового сервера

Рис.1 Установка почтового сервера

Запускаем установщик courierms302_setup.exe

Установка почтового сервера

Рис.2 Установка почтового сервера

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

Установка почтового сервера

Рис.3 Установка почтового сервера

Указываем папку, куда устанавливать Courier Mail Server. В вашем случае это папка C:\server\mail-server.

Установка почтового сервера

Рис.4 Установка почтового сервера

В следеющем шаге, нужно задать имя и пароль администратора для доступа к настройкам сервера. После чего кликаем на кнопку "Далее" и завершаем установку.

Установка почтового сервера

Рис.5 Установка почтового сервера

Установка почтового сервера

Установка планировщика заданий nnСron Lite

Иногда требуется автоматически запускать скрипт по расписанию. Для этой цели подойдет программа cron. Cron – это UNIX-демон, присутствует в любой UNIX-системе и позволяет запускать скрипт по расписанию.

В качестве реализации cron для windows выбрана unix аналог cron – nnCron Lite. Скачать дистрибутив можно отсюда nncronlt117.exe или на официальном сайте разработчика nncron.ru/download.shtml

Установка планировщика заданий nnСron

Создаём папку C:\server\cron Запускаем установщик nncronlt117.exe

Рис. 1 Установка планировщика заданий nnСron

Установка планировщика заданий nnСron

Рис. 2 Установка планировщика заданий nnСron

Принимает лицензионное соглашение и продолжаеми установку. Следующем окне, выбираем компонты установки.

Установка планировщика заданий nnСron

Рис. 3 Установка планировщика заданий nnСron

Далее папку установки C:\server\cron

Установка планировщика заданий nnСron

Рис. 4 Установка планировщика заданий nnСron

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

Установка планировщика заданий nnСron

Рис. 5 Установка планировщика заданий nnСron

Установка крона закончена, теперь нужно сделать так, чтобы в Windows php скрипты воспринимались как исполняемы программы, для чего необходимо связать итерпритатор с расширением php. Для этого выделите любой php-файл и в контекстовом меню выберите пункт “Свойства”

Установка планировщика заданий nnСron

Рис. 6 Установка планировщика заданий nnСron

После чего кликните на кнопку “Изменить“. В открывшимся окне выберите кнопку “Найти“. Далее в диалогом окне выберите файл C:\server\php\php.exe

Установка планировщика заданий nnСron

Рис. 7 Установка планировщика заданий nnСron

В результате этого в окне браузера выбора обработчика php-файлов появится обработчик CLI, как это показано на рисунке 8

Установка планировщика заданий nnСron

Рис. 8 Установка планировщика заданий nnСron

Настройка виртуальных хостов на основе имён.

В этом разделе я расскажу о настройке виртуального хоста на основе доменных имён, благодаря чему, можно расположить на одном физическом серверы множество сайтов с разными доменными именами. В этом случае не нужно, чтобы у каждого виртуального хоста был свой собственных IP-адрес поскольку один IP-адрес распределяется среди нескольких доменных имен. В результате значительно упрощается конфигурирование сети и устраняется необходимость в нескольких аппаратных или программных интерфейсов, а главное, для каждого домена не требуется отдельный ip адрес, что особенно актуально на сегодняшний день, когда диапазон свободных ip v4 практически исчерпаны.

В этои примере мы рассмотрим настройку виртуального хоста на основе 3х сайтов: www.site1.ru, www.site2.ru, www.site3.ru

В папке C:\server\home создаём 3 папки: site1, site2 и site3

Далее в кажой папке site1, site2 и site3, которые вы только что создали, создаём еще 3 папки: cgi-bin, logs и www

Теперь зайдите в папку C:\server\Apache2\conf\extra и откройте в текстовом редакторе уже знакомый вам файл httpd-vhosts.conf. Помните, вы уже добавляли запись для хоста localhost, когда настраивали веб сервер Apache. Сейчас проделываем тоже самое для наших хостов. Добавьте следующую запись:

#site1.ru


# Корневой директорией сайта
DocumentRoot "C:/server/home/site1/www"    
# Доменое имя
ServerName "site1.ru"  
# Алиасы
ServerAlias "www.site1.ru" "site1.ru" 
  
# Директория для CGI-скриптов
ScriptAlias /cgi/ "C:/server/home/site1/cgi/"
ScriptAlias /cgi-bin/ "C:/server/home/site1/cgi-bin/"
  
# Файлы логов
CustomLog "C:/server/home/site1/logs/access.log" common
ErrorLog "C:/server/home/site1/logs/error.log"
  


#site2.ru


# Корневой директорией сайта
DocumentRoot "C:/server/home/site2/www"  
  
# Доменое имя
ServerName "site2.ru"
  
# Алиасы
ServerAlias "www.site2.ru" "site2.ru" 
  
# Директория для CGI-скриптов  
ScriptAlias /cgi-bin/ "C:/server/home/site2/cgi-bin/"
  
# Файлы логов
CustomLog "C:/server/home/site2/logs/access.log" common
ErrorLog "C:/server/home/site2/logs/error.log"
  


#site3.ru


# Корневой директорией сайта
DocumentRoot "C:/server/home/site3/www"  
  
# Доменое имя
ServerName "site3.ru"
  
# Алиасы
ServerAlias "www.site3.ru" "site3.ru" 

# Директория для CGI-скриптов
ScriptAlias /cgi-bin/ "C:/server/home/site3/cgi-bin/"
  
# Файлы логов
CustomLog "C:/server/home/site3/logs/access.log" common
ErrorLog "C:/server/home/site3/logs/error.log"
  

Сохраняем и закрываем файл httpd-vhosts.conf

Чтобы внесенные изменения вступили в силу, перезагружаем Апач.

Ну практически всё, осталось лишь прописать dns запись, где доменные имена www.site1.ru, www.site2.ru и www.site3.ru соответствовали внутреннему ip адресу 127.0.0.1. Это можно сделать добавив dns запись в файл hosts на вашем компьютере

Открываем файл hosts в блокноте. В windows vista/7/8 этот файл находится в папке C:\WINDOWS\system32\drivers\etc и дописываем внизу следующие строки:

127.0.0.1 site1.ru
127.0.0.1 www.site1.ru
127.0.0.1 site2.ru
127.0.0.1 www.site2.ru
127.0.0.1 site3.ru
127.0.0.1 www.site3.ru

Установка Apache, PHP, Perl, MySQL Часть 1
]]>
janickiy@mail.ru (Alexander) Статьи Tue, 18 Feb 2014 08:15:50 +0000
Установка Apache, PHP, Perl, MySQL Часть 1 http://janicky.com/stati/ustanovka-apache-php-perl-mysql http://janicky.com/stati/ustanovka-apache-php-perl-mysql

В этой статье я расскажу Вам как установить и настроить веб сервер Apache, PHP, Perl, почтовый сервер и СУБД MySQL у себя на компьютере, который Вы можете использовать как для тестирования и отладки скриптов, так и для полноценного веб сервера. Конечно, существуют множество готовых решений, например, как Денвер, LAMP, XAMPP, с помощью которых вы сможет легко и быстро установить веб сервер себе на локальный компьютер за 5 минут. Может быть это быстро и удобно, в этом случае, используя готовые инструменты, вам будет проблематично настроить и обновить систему под свои нужды. Устанавливая самостоятельно программное обеспечение, вам не придётся зависит от готовых инструментов, и вы всегда можете настроить систему под cвои нужды. Тем более в этом нет ничего сложного.

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

Установка веб сервера Apache

Начинаем установку с самого главного, а именно, c программы Apache, который будет служить вам веб сервером. Основная причина, по которой был выбран Apache, является то, что это кроссплатформенное программное обеспечение, основанное на свободном исходном коде, безопасен и надёжен в работе, гибок в установке и настройке. Более подробную информацию и документацию, вы можете найти на официальном сайте apache.org

Скачиваем файл установки httpd-2.2.25-win32-x86-openssl-0.9.8r. После того, как скачали, приступаем к установке веб сервера. Для бедующего сервера, создайте папку C:\server, а в ней папку с именем Apache2

Запустите файл httpd-2.2.25-win32-x86-openssl-0.9.8y.msi (расширение .msi будет скрыто), после чего появится окно.

установка apache

Рис.1 Установка веб сервера Apache

Далее кликаем на кнопку "Next", появляется следующее окно с лицензионным соглашением.

установка apache

Рис.2 Установка веб сервера Apache

Выбираем: "I accept the terms in the agreement", чтобы принять лицензионное соглашение. В следующем шаге должно появиться новое окно с описанием веб серрвера Apache.

установка apache

Рис.3 Установка веб сервера Apache

Кликаем на кнопку “Next” и продолжаем установку. Далее появляется следующие окно.

установка apache

Рис.4 Установка веб сервера Apache

В этом окне нам нужно ввести информацию о нашем веб сервере. Заполняем поля следующим образом:
Network domain: localhost
Server name: localhost
Administrator’s email: admin@ localhost

установка apache

Рис.5 Установка веб сервера Apache

После того как вы заполнили все поля, кликаем на кнопку “Next”. Должно появиться новое окно.

установка apache

Рис.6 Установка веб сервера Apache

В этом окне вам предлагают выбрать тип установки, полную (Typical) и выборочную(Custom). Выбираем “Custom” и продолжаем установку.

установка apache

Рис.7 Установка веб сервера Apache

В следующем шаге вам нужно выбрать куда устанавливать, а также дополнительные библиотеки. Кликаем на против креcтика “Build Headers and Libraries”, в выпадающем списке выбираем “This features will be installed on local hard drive” Потом выбираем папку, куда устанавливать Apache. Вместо C:\Program Files (X86)\Apache Software Foundation\Apache 2.2 указываем C:\server\Apache2\ и кликаем на сново на кнопк “Next

установка apache

Рис.8 Установка веб сервера Apache

Должно появиться заключительное окно.

установка apache

Рис.9 Установка веб сервера Apache

Кликаем на кнопку “Install”, чтобы начать процесс установки.

установка apache

Рис.10 Установка веб сервера Apache

Ждем завершения процесса установки, после чего должно появиться окно с сообщение, что процесс установки завершен.

установка apache

Рис.11 Установка веб сервера Apache

Кликаем на кнопку “Finish” и завершаем установку. Всё, теперь установка веб сервера завершена. Чтобы убедиться в этом, смотрим в правом нижнем углу, вы должны увидеть значок, как показано на рисунке 12.

установка apache

Рис.12 Установка веб сервера Apache

Если этот так, значит веб сервер запущен как служба. Если по какой-либо причине Apache не был запущен, то возможная из причин, что 80 порт занят другой программой. Решить проблему, можно отключив программу, которая занимает 80 порт. Чтобы это выяснить, набираем в командной строке:

netstat -o -n -a | findstr 0.0:80

установка apache

Рис.13 Установка веб сервера Apache

Очень часто 80 порт занимает программы Skype Если '80 порт занимает это так, отключите в настройках использование в качестве альтернативных портов 80 и 443 (Инструменты -> Настройки -> Расширенный настройки -> Соединение -> снимаем галочку (Использовать порты 80 и 443 в качестве альтернативных)

Проверяем работоспособность установленого веб сервера. Открываем браузер и набираем в адресной строке http://localhost или http://127.0.0.1 Если вы видите, тоже самое, что на рисунке 14. Поздравляю, ваш веб сервер установлен удачно!

установка apache

Рис.14 Установка веб сервера Apache

Настройка веб-сервера Apache

Теперь нам осталось настроить Apache. Открываем в блокноте файл конфигурации Apache httpd.conf, который лежит в папке C:\server\Apache2\conf Стираем в нём всё и вписываем следующие:

установка apache

Рис.15 Установка веб сервера Apache


# Количество потоков, созданных каждым дочерним процессом.
ThreadsPerChild 25

# Количество запросов, которое должен обработать дочерний процесс Apache 
MaxRequestsPerChild  0

# Величина таймаута для сервера
Timeout 300

# Корневая папка веб сервера
ServerRoot "c:/server/Apache2"

# Порт, который слушает наш веб сервер
Listen 80

# Модули
LoadModule actions_module modules/mod_actions.so
LoadModule alias_module modules/mod_alias.so
LoadModule asis_module modules/mod_asis.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authn_default_module modules/mod_authn_default.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authz_default_module modules/mod_authz_default.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule cgi_module modules/mod_cgi.so
LoadModule dir_module modules/mod_dir.so
LoadModule env_module modules/mod_env.so
LoadModule imagemap_module modules/mod_imagemap.so
LoadModule include_module modules/mod_include.so
LoadModule isapi_module modules/mod_isapi.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module modules/mod_mime.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule userdir_module modules/mod_userdir.so

# Имя сервера
ServerName localhost

# Корневая папка для веб документов
DocumentRoot "c:/server/Apache2/htdocs"

# Директива правил безопасности.

    Options Includes Indexes FollowSymLinks
    AllowOverride All
    Order deny,allow
    Allow from all
    Satisfy all


# E-mail администратора
ServerAdmin admin@localhost

# Индексные файлы
DirectoryIndex index.htm index.html index.shtm index.shtml index.php index.php4 index.php5

# Тип заголовков

    TypesConfig conf/mime.types
    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
    AddHandler cgi-script .cgi .pl .py
    AddType application/x-httpd-php .php .php5 .phtml
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml .html


# Закрываем доступ к файлам конфигурации (.htaccess) и паролей

    Order allow,deny
    Deny from all


# Файл отчёта с ошибками
ErrorLog logs/error.log

# Обработка ошибок
LogLevel warn

# Шаблон записи строки в файл отчёта

    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    

    CustomLog logs/access.log common

    #CustomLog logs/access.log combined


# Тип всех документов - текстовый
DefaultType text/html

# Дополнительные файлы конфигуразии веб сервера
Include conf/extra/httpd-autoindex.conf
Include conf/extra/httpd-vhosts.conf
Include conf/extra/httpd-manual.conf

# Модуль обеспечивающий работу по протоколу HTTPS

SSLRandomSeed startup builtin
SSLRandomSeed connect builtin


# Модуль Мультиобработки
Win32DisableAcceptEx On

Сохраняем и закрываем файл httpd.conf После того как вы внесли изменения в основной конфигурационный файл, время создать виртуальный хост. Заходим в папку C:\server и создаём в ней папку home.

установка apache

Рис.16 Установка веб сервера Apache

В папке home папку localhost, в которой создаём ещё 3 паки cgi-bin, logs. В папке www, будут храниться php, html и другие файлы витального хоста. В папке cgi-bin, будут храниться perl скрипты. В папке log, логи веб сервера. Cодержимое папки localhost выглядит так, как показано на рисунке

установка apache

Рис.17 Установка веб сервера Apache

Теперь заходим в папку C:\server\Apache2\conf\extra и открываем в блокноте файл httpd-vhosts.conf (расширение .conf скрыто) прописываем туда виртуальные хосты. Удаляем содержимое этого файла и вписываем следующие.

#localhost
NameVirtualHost 127.0.0.1:80

  DocumentRoot "C:/server/home/localhost/www"  
  ServerName "localhost"
  ServerAlias "www.localhost" "localhost" 
  ScriptAlias /cgi-bin/ "C:/server/home/localhost/cgi-bin/"  
  CustomLog "C:/server/home/localhost/logs/access.log" common
  ErrorLog "C:/server/home/localhost/logs/error.log" 

Сохраняем и закрываем httpd-vhosts.conf Перезагружаем Apache, чтобы изменения вступили в силу. Для этого кликните левой кнопкой мыши в правом нижнем углу на значок “Apache Service Monotor”, а затем в выпадающем списке выберите “Restart

Установка PHP итепритатора

Для того, чтобы ваш веб сервер обрабатывал php файлы, необходимо установить интопритатор php файлов.

Установка PHP итепритатора

Рис.1 Установка PHP итепритатора

Установка PHP возможна двумя вариантами: как модуль Apache и как внешнее CGI-приложение. Мы выбираем первый вариант, потому что PHP в качестве модуля немного повышает быстродействие, так как модуль PHP загружается один раз при запуске Web-сервера.

В папке C:\server создаём папку php для файлов php дистрибутва. Скачивам архив с дистрибудивом php php5-4-25.zip себе на локальный компьютер и распаковываем содержимое архива в папку C:\server\php Теперь необходимо сообщить Apache о наличие установленного php. Снова открываем уже знакомый файл Apache httpd.conf и добавляем туда эти строчки:

PHPIniDir "C:/server/php5/" 
LoadModule php5_module "C:/server/php/php5apache2_2.dll"

Открываем блокнот и добовляем следующие строчки:


Установка PHP интерпретатора

Рис.2 Установка PHP интерпретатора

Даём имя index.php и сохраняем в папке C:\server\home\localhost\www

Проверяем, если PHP итерпритатор установлен правильно, то в окне своего браузера, набрав в адресной строке http://localhost/index.php, вы увидите сообщение, как показано на рисунке 3.

Установка PHP интерпретатора

Рис.3 Установка PHP итепритатора

Установка Perl интерпретатора

Для того, чтобы на вашем веб сервере выполнялись скрипты написаные на языке Perl, вам необходимо установить интерпритарор языка perl.

В папке C:\server создаём папку perl. Скачиваем дистрибутив perl strawberry-perl-5.20.1.1-64bit.msi После того, как вы скачали дистрибутив, запустите файл установки strawberry-perl-5.20.1.1-64bit.msi (расширение .msi будет скрыто). Должно появится окно:

Установка Perl интерпретатора

Рис.3 Установка Perl итепритатора

Кликаем на кнопку “Next”, сразу после этого появится окно лицензионого соглашения:

Установка Perl интерпретатора

Рис.4 Установка Perl итепритатора

Чтобы принять лицензионное соглашение и продолжить установку, выбираем “I accept the terms in the License Agreement”. В следующем окне вписываем куда будем устанавливать дистрибутив, папку C:\server\perl

Установка Perl интерпретатора

Рис.5 Установка Perl интерпретатора

Кликаем на кнопку “Inslall”, чтобы запустить процесс установки.

Установка Perl интерпретатора

Рис.6 Установка Perl интерпретатора

Подождите, пока Мастер установки скопирует и установит файлы на ваш компьютер, после чего проверяем работоспособность. Открываем блокнот, создаём файл с именем tesp.pl и вписываем в него следующие:

#!C:\server\perl\perl\bin\perl.exe
print "Content-type: text/html\r\n\r\n";
print "Hello, World!"; 

Сохраняем этот файл в папке C:\server\home\localhost\cgi-bin.

Открываем браузер, в адресной строке вводим http://localhost/cgi-bin/test.pl. Ели интерпритатор установлен правильно, вы увидите следующие:

Установка Perl интерпретатора

Рис.7 Установка Perl интерпретатора


Продолжение: Установка Apache, PHP, Perl, MySQL Часть 2
]]>
janickiy@mail.ru (Alexander) Статьи Mon, 17 Feb 2014 13:17:56 +0000
Удалить каталог вместе с его содержимым http://janicky.com/stati/udalit-katalog-vmeste-s-ego-soderzhimym http://janicky.com/stati/udalit-katalog-vmeste-s-ego-soderzhimym

Для удаления каталога со всем его содержимым необходимо осуществить рекурсивный спуск, удаляя перед использованием функции rmdir() е файлы при помощи функции unlink();

]]>
janickiy@mail.ru (Alexander) Статьи Fri, 18 Oct 2013 08:22:11 +0000
Загрузка файлов на сервер http://janicky.com/stati/zagruzka-faylov-na-server http://janicky.com/stati/zagruzka-faylov-na-server

Для того, чтобы обеспечить произвольное количество полей под загружаемые файлы, необходимо воспользоваться клиентским языком JavaScript, который позволит динамически сформировать HTML-форму. Для рабаты скрипта необходимо, чтобы в том же каталоге, где расположено Web-приложение, имелся подкаталог file, содержащий файл, права доступ к которым были настроены таким образом, чтобы скрипт имел право записи в каталог.

HTML-форма загрузки


Обработчик HTML-формы


	";
}

Атрибут enctype формы определяет вид кодировки, которую браузер применяет к параметрам формы. Чтобы отправка файла на сервер действовала, атрибуту enctype необходимо присвоить значение multipart/form-data. По умолчанию этот атрибут имеет значение application/x-www-form-urlencoded. Если данный атрибут не объявляется, загрузка файла на сервер невозможна.

HTML-форма состоит из произвольного количества полей типа file. Если в качестве имен нескольких элементов управления HTML-формы выступает массив, в обработчике формы значение из данного элемента можно получить, обратившись к суперглобальному элементу $_POST[‘имя_массива’][]. В HTML-форме все поля типа file объединяются в массив под одним именем att[], доступ к которому в обработчике осуществляется при помощи массива $_POST[‘att’]. Индексы массива нумеруются с нуля. Это приводит, к тому, что обработка файла производится в цикле. При помощи функции copy() файл копируется из временного каталога в каталог значения files. Потом временный файл уничтожается при помощи функции unlink(), а файлу в каталоге files назначаются права доступа 0644.

]]>
janickiy@mail.ru (Alexander) Статьи Sun, 04 Aug 2013 19:51:20 +0000
Создание PHP календаря http://janicky.com/stati/sozdanie-php-kalendarya http://janicky.com/stati/sozdanie-php-kalendarya

В этой статье я расскажу как создать функциональный календарь с использованием PHP. Около года назад мне поручили сделать календарь событий на одном сайте. Заказчик не очень жаловал javascript или ajax, поэтому настоял на использовании PHP. Это было довольно интересный опыт. Мне пришлось забыть свои мечты о быстром выполнении заказа с использованием jQuery datepicker. Я уже приготовился к тому, что мне предстоит тяжелая работа. Потом меня осенило. Ведь календарь, по сути, является ни чем иным как системой циклических чисел. Чем больше я об этом думал, тем легче мне начинала казаться задача. В конце концов, после небольшого исследования о функциях даты PHP, я придумал способ, который действительно сработал. Рабочий пример можно скачать здесь.

Начнем с установки нескольких переменных среды. Очевидно, что нам необходимо знать URL нашего скрипта, и, поскольку мы работаем с календарем, нам нужна дата, от которой мы будем отталкиваться. Нам нужно проверить, указывает ли назначенная на наш URL переменная на конкретный год, месяц и день. Если нет, то мы начнем с сегодняшней даты.

Следующая задача будем немного сложнее, чем кажется, когда мы впишем ее в код. Мне нужно было изменить год, когда наступал следующий за декабрем месяц. Позже вы увидите, что то же самое нужно будет делать и на тот случай, если календарь будет просматриваться в обратную сторону.

Теперь давайте используем установленные выше значения месяца и года, чтобы выяснить, на какой день выпадет начало нового месяца. К счастью, mktime идеально подойдет для этой задачи. Если кто не знает, в mktime передаются следующие значения: Час, Минута, Секунда, Месяц, День и Год. Затем он выдает временную метку Unix для этого момента времени.

 "январь",
"2" => "февраль",
"3" => "март",
"4" => "апрель",
"5" => "май",
"6" => "июнь",
"7" => "июль",
"8" => "август",
"9" => "сентябрь",
"10" => "октябрь",
"11" => "ноябрь",
"12" => "декабрь"); 

$first_of_month = mktime(0, 0, 0, $month, 1, $year); 

// Массив имен всех дней в неделю
$day_headings = array('Sunday', 'Monday', 'Tuesday', 
'Wednesday', 'Thursday', 'Friday', 'Saturday'); 

$maxdays = date('t', $first_of_month); 
$date_info = getdate($first_of_month); 
$month = $date_info['mon']; 
$year = $date_info['year']; 

// Если текущий месяц это январь, 
//и мы пролистываем календарь задом наперед число, 
//обозначающее год, должно уменьшаться на один. 

if($month == '1'): 
    $last_year = $year-1; 
else: $last_year = $year; 
endif; 

// Вычитаем один день с первого дня месяца, 
//чтобы получить в конец прошлого месяца
$timestamp_last_month = $first_of_month - (24*60*60); 
$last_month = date("m", $timestamp_last_month);

// Проверяем, что если месяц декабрь, 
//на следующий месяц равен 1, а не 13
if($month == '12')
    $next_month = '1'; 
else $next_month = $month+1; 

?>

Как видите, мы потратили достаточно много времени на то, чтобы убедиться, что мы знаем наше положение во времени и можем влиять на то, что произойдет, когда значения дней, лет и месяцев будут уменьшаться или увеличиваться при просмотре календаря. Важно помнить, что при работе с датами всегда полезно устанавливать значения по умолчанию, прежде чем приступать к созданию кода. Нельзя точно знать, что вам понадобиться, но по ходу выполнения задачи вам почти наверняка нужно будет узнать текущий день, месяц и год. Мы снова используем функцию даты() в PHP и mktime(), чтобы точно манипулировать числами. Далее мы начинаем чертить календарь.


"; 
?>

Выше мы сделали заголовок таблицы и ссылки навигации, чтобы переходить вперед и назад по месяцам и годам в календаре. Теперь мы печатаем дни, выделяя сегодняшнюю дату. Каждый день – это ссылка на тот день, на который мы можем перейти. Теперь будет просто создать систему событий, так как день, месяц и год, на которые вы кликаете, указывает на URL, благодаря чему вы можете просматривать установки и показывать события согласно этому.

 0) 
    $calendar .= "
"; while($day <= $maxdays) { // если суббота, выволдим новую колонку. if($weekday == 7) { $calendar .= ""; $weekday = 0; } $linkDate = mktime(0, 0, 0, $month, $day, $year); // проверяем, если распечатанная дата является сегодняшней датой. //если так, используем другой класс css, чтобы выделить её if((($day < 10 and "0$day" == date('d')) or ($day >= 10 and "$day" == date('d'))) and (($month < 10 and "0$month" == date('m')) or ($month >= 10 and "$month" == date('m'))) and $year == date('Y')) $class = "caltoday"; //в противном случае, печатаем только ссылку на вкладку else { $d = date('m/d/Y', $linkDate); $class = "cal"; } //помечаем выходные дни красным if($weekday == 5 || $weekday == 6) $red='style="color: red" '; else $red=''; $calendar .= " "; $day++; $weekday++; } if($weekday != 7) $calendar .= ""; // выводим сам календарь echo $calendar . "
Пн Вт Ср Чт Пт Сб Вс
{$day}
"; ?>

Хотите - верьте, хотите – нет, но на этом все. Теперь можно кликать на каждый день календаря, переходить на месяцы и годы, нажимая на стрелки рядом с названием месяца в заголовке таблицы. Сегодняшняя дата отличается от всех остальных своим классом CSS, поэтому ее можно стилизовать по своему усмотрению, и у нас получился довольно гибкий календарь. В завершение хочу включить в наш проект небольшую форму, которая позволит вам переходить на любой месяц любого года на двадцать лет вперед. Также хочу предложить ссылку для перехода на текущий месяц. Код очень простой:


";
echo "";

if($month != date('m') || $year != date('Y'))
	echo "<< Вернуться к текущей дате";
echo "
"; ?> php календарь

Понравилась статья?

]]>
janickiy@mail.ru (Alexander) Статьи Tue, 29 Jan 2013 14:57:03 +0000
Работа с ZIP архивами в PHP http://janicky.com/stati/rabota-s-zip-arhivami-v-php http://janicky.com/stati/rabota-s-zip-arhivami-v-php

Расширение архива Zip в PHP используется для работы с Zip архивами и файлами, которые в них содержатся. Для использования этого расширения в PHP 5 необходимо активировать php_zip.dll внутри файла php.ini. В этой статье вы узнаете о том, как работать с файлами Zip архивов в PHP, используя ряд PHP демо-приложений. Вы научитесь: создавать Zip архивы;

  • создавать Zip архивы;
  • добавлять файлы и папки в архив из строки и данной дорожки;
  • удалять и переименовывать файлы, используя их индексы и имена;
  • составлять список характеристик объектов ZipArchive (количество файлов, имя файла, комментарии, statusSys и т. д.).

Создание Zip архивов в PHP и добавление файлов

Для создания Zip архива в PHP можно использовать предопределенную константу ZIPARCHIVE::CREATE; архив будет создан, если он еще не существует. (Для добавления файлов внутрь архива можно использовать вышеописанные методы addFile и addFromString.) Первое демо-приложение (add_file_from_string.php) создает (если таковой еще не существует) или открывает Zip архив archive1.zip, а после добавляет в него файл, используя метод addFromString():

bool ZipArchive::addFromString ( string $localname , string $contents ): Добавить файл в Zip-архив, используя его содержание.

Здесь код для add_file_from_string.php:

С результаты выполнения add_file_from_string.php вы также можете ознакомиться на Рисунке 1.

Файловый текст test1.txt был успешно добавлен в archive1.zip

Рис.1 The archive1.zip

Рис.1 The archive1.zip

Второе демо-приложение (add_file_directory.php) также использует архив archive1.zip для печати всех характеристик объекта ZipArchive (статус, statusSys, numFiles, название файла, комментарии или специальные параметры, в нашем случае архивный комментарий и количество файлов), чтобы добавить пустой каталог под названием Subdirectory1. Это приложение также использует архив archive1.zip для добавления нового файла, используя метод addFile. Ниже содержатся прототипы методов addFile() и addEmptyDir():

bool ZipArchive::addFile ( string $filename [, string $localname ] ) : добавляет файл в Zip-архив с даного пути bool ZipArchive::addEmptyDir ( string $dirname ) : добавляет пустую папку в архив.

Здесь код для add_file_directory.php:

 
open('archive1.zip');

// Подробный список всех ZipArchive объектов
print_r($zip);

//Добавление пустого каталога
if($zip->addEmptyDir('Subdirectory1')) {
        echo 'Создан новый каталог'. "
"; } else { echo 'Не могу создать директорию'. "
"; } //Добавление нового текстового файла test2.txt $zip->addFile('test2.txt'); //Список комментариев архива archive1.php echo "Комментарий: " . $zip->comment . "
"; //Список номеров фалов архива archive1.php echo "№ файла:" . $zip->numFiles . "
"; ?>

С результатом листинга add_file_directory.php вы также можете ознакомиться на Рисунке 2:

ZipArchive Object ( [status] => 0 [statusSys] => 0 [numFiles] => 2 [filename] => D:\Apache Group\Apache2\htdocs\php\ZIP\archive1.zip [comment] => PHP ZIP ARCHIVE ) Создан новый каталог Комментарий: PHP ZIP ARCHIVE № файла:4

Характеристики объекта archive2.zip

Рисунок 2. Характеристики объекта archive2.zip

Следующее демо-приложение служит для создания Zip архива archive2.zip, который включает два файла: test3.txt и test4.txt. (Информацию о том, как пользоваться этим приложением, вы сможете найти ниже.) Код для archive2.php:

Результат archive2.php. Вы также можете ознакомиться с результатами на Рисунке 3: Файловый текст test3.txt успешно добавлен в archive2.zip при использовании метода addFile Файловый текст test4.txt успешно добавлен в archive2.zip при использовании метода addFromString method.

Содержание archive2.zip

Рисунок 3. Содержание archive2.zip

Извлечение Zip архива в PHP

Демо-приложение этой части (extract_archives.php) показывает, как извлекать содержимое архива в специальную папку, используя метод extractTo():bool ZipArchive::extractTo ( string $destination [, mixed $entries ] ) : извлечь содержимое архива.

Архивы archive1.zip и archive2.zip будут извлечены в папку archive, как показано на Рисунке 4. Код для extract_archives.php:

 open('archive1.zip');
$extract2 = $zip2->open('archive2.zip');

if (($extract1 === TRUE) && ($extract2 === TRUE)) {
    
    //Извлекаем содержимое архива
    $zip1->extractTo('archive');
    $zip2->extractTo('archive');

    //Закрываем Zip-архив
    $zip1->close();
    $zip2->close();
    echo 'Архивы archive1.zip и archive2.zip были извлеченны в папку!';

} else {
       echo 'Извлечение archive1.zip и archive2.zip не удалось!';
}

?> 

Результат extract_archives.php: archive1.zip и archive2.zip были извлечены в папку archive!

Содержимое папки archive после извлечения archive1 и archive2

Рисунок 4. Содержимое папки archive после извлечения archive1 и archive2

Следующее демо-приложение (extract_to_specified_folder.php) извлекает содержимое Zip архива в специальную папку, используя вышеописанный метод extractTo(). Код для extract_to_specified_folder.php:

 open('archive1.zip') !== TRUE) {
    die ("Не могу окрыть архив");
}

// извлекаем содержимое в папку назначения
$zip->extractTo('../ZIP_extract/');

//Закрываем архив
$zip->close();    
echo "Архив извлечен в папку ZIP_extract!";

?> 

Результат extract_to_specified_folder.php. Вы также можете ознакомиться с результатами на Рисунке 5: Архив извлечен в папку ZIP_extract!

Папка ZIP_extract с файлами archive1

Рисунок 5. Папка ZIP_extract с файлами archive1



 open('archive2.zip') !== TRUE) {
    die ("Не могу октыть архив");
}

//Извлекаем выбраные файлы в назначеную директорию ZIP_TEST
$fileList = array('test3.txt','test4.txt');
$zip->extractTo('../ZIP_TEST/', $fileList);

//Закрываем архив
$zip->close();    
echo "Файлы test3.txt и test4.txt извлечены успешно из рахива archive2.zip в указанный каталог!";
?>

С результатами листинга filelist.php вы также можете ознакомиться с на Рисунке 6: Файлы test3.txt и test4.txt из архива archive2.zip успешно извлечены в указанный каталог ZIP_TEST!

Выбранные файлы, извлеченные из archive2 в назначеный каталог ZIP_TEST

Рисунок 6.Выбранные файлы, извлеченные из archive2 в назначеный каталог ZIP_TEST

Получение характеристик объекта на основе его индекса

Для получения характеристик отдельного файла можно использовать метод statIndex:

mixed ZipArchive::statIndex ( int $index [, int $flags ] ).

Следующее демо-приложение (statIndex.php) итерирует список файлов в archive2.zip и печатает характеристики для каждого из объектов. Код для statIndex.php:

 open('archive2.zip') !== TRUE) {
    die ("Не могу открыть архив");
}

//Получаем номер файла в архиве archive2.zip
$numFiles = $zip->numFiles;

//Переборираем списк файлов
for ($i=0; $i<$numFiles; $i++) {

    //Получаем подробную информацию записи определеную её индексом
    print_r($zip->statIndex($i));
    print "
"; } //закрываем архив $zip->close(); ?>
Результат листинга 5.php:
Array ( 
[name] => test3.txt
[index] => 0 [crc] => -1117485446
[size] => 45 
[mtime] => 1269720238
[comp_size] => 46 [comp_method] => 8 )


Array (
[name] => test4.txt 
[index] => 1 [crc] => -1780851877 
[size] => 77 
[mtime] => 1269786772 
[comp_size] => 62 
[comp_method] => 8 )

Следующее демо-приложение (locate.php) также позволяет получать характеристики файла, при условии что archive1.zip содержит этот файл. Метод locateName возвращает индекс файла в архиве и использует предопределенную константу ZIPARCHIVE::FL_NODIR, которая игнорирует компонент каталог. Прототип константы ZIPARCHIVE::FL_NODIR :

mixed ZipArchive::locateName ( string $name [, int $flags ] )

Код для locate.php:

open('archive1.zip') === TRUE) {
    
//Находим указаный файл в архиве и выводим его подробную информацию
$locate_file = $zip->locateName('test2.txt', ZIPARCHIVE::FL_NODIR);
if ($locate_file == TRUE) {
    $file = $zip->statIndex($locate_file);
    print_r($file);
}

// закрываем архив
$zip->close();
} 
Результат листинга locate.php:

Array ( [name] => test2.txt [index] => 2 [crc] => -513033757 [size] => 50 [mtime] => 1269715222 [comp_size] => 49 [comp_method] => 8 )

Удаление и переименование Zip архивов в PHP

Для удаления или переименования Zip архивов в PHP можно использовать имя или индекс. Методы, которыми можно воспользоваться для этой цели, включают:

bool ZipArchive::deleteIndex ( int $index ) – Удаляет объект в архиве, используя индекс; bool ZipArchive::deleteName ( string $name ) – Удаляет объект в архиве, используя имя; bool ZipArchive::renameIndex ( int $index , string $newname ) – Переименует объект на основе индекса; bool ZipArchive::renameName ( string $name , string $newname ) – Переименует объект на основе имени.

Следующее демо-приложение (rename.php) использует все вышеперечисленные методы для переименования файла с "index=3", как "renameByIndex.txt", и "test4.txt", как "renameByName.txt". Код для rename.php:

 open('archive2.zip') !== TRUE) {
    die ("Не могу открыть архив");
}

// переменовываем файл в архиве по его индексу
$zip->renameIndex(0, 'renamedByIndex.txt') or die("ERROR: не могу переменовать файл");

// переменовываем файл в архиве по его имени
$zip->renameName("test3.txt", "renamedByName.txt") or die("ERROR: не могу переменовать файл");

// закрываем и сохраняем архив
$zip->close();
echo "Файл усепшно переменован в архиве archive2.zip!";
?> 

Результаты листинга rename.php. Вы также можете ознакомиться с результатами на Рисунке 7 и Рисунке 8: Файлы успешно переименованы в архиве archive2.zip!

Исходное содержимое archive2.zip

Рисунок 7. Исходное содержимое archive2.zip

Содержание архива archive2.zip после того, как файлы были переименованы

Рисунок 8. Содержание архива archive2.zip после того, как файлы были переименованы

Следующее приложение (delete.php) удаляет из archive2.zip файл с "index=1" и текстовый файл renameByIndex.txt, используя методы deleteIndex() и deleteName(). Код для delete.php:

 open('archive2.zip') !== TRUE) {
    die ("Could not open archive");
}

//Удаляем файл с индексом=1 из архива archive2.zip
$zip->deleteIndex(0) or die("ERROR: Не могу удалить файл с индексом=1 ");

//Удалаяем файл test3.txt из архива archive2.zip
$zip->deleteName('renameByIndex.txt') or die("ERROR: Не могу удалить файл test3.txt");

echo "Файл был удалён из архива archive2.zip!";

// закрываем и сохраняем архив
$zip->close();
?> 

В связи с тем, что архив содержал всего два файла и оба были удалены, archive2.zip был также удален. Следующее приложение (add_text_files.php) итерирует архивные файлы и добавляет все файлы .txt из настоящего каталога в text_archive.zip. Код для add_text_files.php:

 open('text_archive.zip', ZIPARCHIVE::CREATE) !== TRUE) {
    die ("Could not open archive");
}

//Добавленпие всех файлов с расширением .txt из текущего каталога в архив text_archive.zip
foreach (glob ('*.txt') as $textfile) {
    $zip->addFile($textfile);
}

//Закрываем архив
$zip->close();

echo "Архив text_archive.zip был спешно создан!";

?> 

Результаты листинга add_text_files.php: text_archive.zip успешно создан!

Группировка всех текстовых файлов из текущего каталога в новый архив text_archive.zip

Рисунок 9. Группировка всех текстовых файлов из текущего каталога в новый архив text_archive.zip

Заключение

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

Понравилась статья?

]]>
janickiy@mail.ru (Alexander) Статьи Thu, 24 Jan 2013 14:53:42 +0000
Сохранение изображений в базе данных MySQL http://janicky.com/stati/sohranenie-izobrazhenij-v-baze-dannyh-mysql http://janicky.com/stati/sohranenie-izobrazhenij-v-baze-dannyh-mysql

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

Прежде всего, Вы должны создать новую базу данных, для хранения бинарных данных. Для примера используется следующая таблица. Зайдите в phpMyAdmin, скопируйте и вставьте ниже приведённый код:

CREATE TABLE binary_data (
id INT(4) NOT NULL AUTO_INCREMENT PRIMARY KEY,
description CHAR(50),
bin_data LONGBLOB,
filename CHAR(50),
filesize CHAR(50),
filetype CHAR(50)
);

Пример php скрипта для сохранения данных в базе данных

Скрипт store.php сохраняет изображение в базу данных переданное через html форму.




Сохранение бинарных данных в базе данных MySQL



        Проверте параметры подключения к базе данных.");
    }

    $data = addslashes(fread(fopen($_FILES['file']['tmp_name'], "r"), 
    filesize($_FILES['file']['tmp_name'])));

    $_POST['form_description'] = trim($_POST['form_description']);
    $size = filesize ($_FILES['file']['tmp_name']);
 
    $result=$dbh->prepare("INSERT INTO binary_data (description,bin_data,filename,filesize,filetype) 
	"."VALUES ('".$_POST['form_description']."',
	'".$data."',
	'".$_FILES["file"]["name"]."',
	'".$size."',
	'".$_FILES["file"]["type"]."')");
 
	if(!$result) exit("Ошибка выполнения SQL запроса!");
	
	$result->execute(); 
	$id = $dbh->prepare();

	echo "

Этот файл имеет следующий идентификатор (ID) в базе данных: ".$id.""; } else { // отображаем форму для оправки новых данных: ?>

Описание файла: Файл для загрузки/хранения в базе данных:

При выполнении скрипта Вы увидите простую html форму. Для выбора файла (например, изображение) используйте кнопку "Обзор". Затем нажмите кнопку "Отправить". После загрузки файла на веб-сервер скрипт сообщит вам его идентификатор базы данных (ID). ID необходим для получения доступа к информации (при помощи следующего скрипта). Пример php скрипта для вывода изображений в браузер Скрипт getdata.php – это пример скрипта, который извлекает двоичную информацию из базы данных и передает её непосредственно пользователю. getdata.php


	Проверте параметры подключения к базе данных.");
}

$query = "SELECT bin_data,filetype from binary_data WHERE id=".$_GET['id'];
$result = $dbh->query($query);

if(!$result) exit("Ошибка выполнения SQL запроса!");

$row = $result->fetch_array();
 
Header( "Content-type: ".$row['filetype']."");
echo $row['bin_data'];

?>

Поскольку скрипту необходимо "знать", который файл извлекать, в качестве параметра необходимо указать его ID. Например: Файл сохранен в базе данных под ID 2. Для получения этого файла необходимо вызвать:

getdata.php?id=2

Если в базе данных сохранены изображения, на вашей веб-странице можно использовать скрипт getdata, как например : Например: В базе данных вы сохранили изображение как ID 3 и хотите, чтобы оно отобразилось на вашей веб-странице. Для этого воспользуйтесь следующим кодом:

Пару полезных советов.

Как сохранить файл, размер которого больше 2 Mб?

Для загрузки и сохранения файлов, чей размер превышает 2 Мб, необходимо внести несколько изменений в скрипт и php/sql настройки в связи с установленными по умолчанию ограничениями. Для хранения файлов размером 2 Мб следует сделать следующее:

Внесите изменения в скрипт store.php. Поменяйте значение MAX_FILE_SIZE на 24000000;

По умолчанию php позволяет передовать файлы размером не более 2 Мб. Необходимо изменить переменную максимального размера файла на 24M. Это можно сделать в php.ini в дириктиве setting upload_max_filesize или в .htaccess прописать строчку php_value upload_max_filesize 24M. В конфигурационных файле apache прописать LimitRequestBody 24000000.

По умолчанию в mysql можно импортировать файлы размером не более 2 Мб. Чтобы снять ограничения размера пакета в mysql, выполните слудующие действия. Откройте файл настройки my.ini, измените строчку innodb_additional_mem_pool_size = 24M

Чтобы изменения вступили в силу, перезагрузите веб сервер Apache и сервер базы данных MySQL.

Понравилась статья?

]]>
janickiy@mail.ru (Alexander) Статьи Thu, 24 Jan 2013 14:51:57 +0000
Создавайте динамические изображения с ImageMagick http://janicky.com/stati/sozdavaite-dinamicheskie-izobrazheniya-s-imagemagick http://janicky.com/stati/sozdavaite-dinamicheskie-izobrazheniya-s-imagemagick

Цифровое изображение и графика делают веб-сайты визуально более привлекательными и интуитивно понятными в управлении. Они могут передать идею со 100-процентной точностью и позволяют вместо тысячи слов использовать одну единственную картинку. Однако огромное количество изображений в сети Интернет имеют один большой недостаток – они статичны. Размер, разрешение, цвета и другие характеристики, которыми обладают изображения при первоначальной загрузке на веб-сервер, не меняются.

Статические изображения вашего сайта не способны видоизменяться в ответ на действия пользователей сайта, вне зависимости от того, насколько важным это может быть для них. Более того, вы – единственный, кто имеет возможность вносить изменения в изображения. Здесь возможна только ручная работа, и от вас потребуется сначала изменить картинки на рабочем столе, а затем заново загрузить их на веб-сервер.

Представьте себе, какие возможности откроются перед вами, если изображения на вашем сайте смогут видоизменяться в зависимости от того, что делаете вы или другие авторизованные посетители сайта. Речь идет не просто об изменении месторасположения изображения на странице. Мы говорим о таких характеристиках как размер, разрешение, границы, контраст и сглаживание переходов. Представьте себе, что вы сможете автоматически вращать изображение, переворачивать, добавлять оттенки или соединять различные рисунки в одно целое.

Вы сможете увеличивать план города без необходимости хранения отдельных версий этого изображения на вашем сервере (по одной версии для каждого уровня разрешения, который может затребовать пользователь); вы сможете изменять цвета изображения для посетителей сайта, указавших наличие определенной формы цветовой слепоты; пользователи смогут вращать аэрофотоснимки по своему усмотрению, а покупатели изменять оттенки художественных репродукций до того, как совершить покупку. Вы даже сможете создать свой онлайн графический редактор (как, например, GIFWorks.com). Магия цифрового изображения

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

В этой статье я решил использовать ImageMagick по следующим причинам:

  • он лучше подходит к услугам веб-хостинга, чем другие пакеты программ;
  • он бесплатный;
  • он работает на платформах Windows и Linux;
  • на протяжении двух десятилетий он непрерывно усовершенствовался, а ошибки устранялись;
  • он надежный и мощный, а также предлагает расширенные возможности.

Руководство по загрузке и установке ImageMagick можно найти на веб-сайте www.imagemagick.org.

ImageMagick предлагает большое количество функций, но их управление должно осуществляться из командной строки. Для получения доступа к данным функциональным возможностям с вашего веб-сайта на основе PHP вам понадобится API (как PHP расширение), например MagickWand или imagick. В примерах ниже используются API MagickWand, поэтому для продолжения работы вам понадобится установить его на ваш веб-сервер (так же как и ImageMagick).

Использование различных команд в приложении (в дополнение к команде «Abracadabra»)

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

Исходное изображение, отображаемое в браузере

Рисунок 1: Исходное изображение, отображаемое в браузере

Как только вы создаете ресурс MagickWand и загружаете изображение, вы можете узнать информацию об изображении, например размеры:

Определение размеров изображения

Рисунок 2: Определение размеров изображения

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

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

 Обрезанное изображение

Рисунок 3: Обрезанное изображение

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

Масштабированное изображение

Рисунок 4: Масштабированное изображение

Изображение выше иллюстрирует, как функция MagickTransformImage автоматически сохраняет соотношение размеров изображения при масштабировании.

Также учтите, что MagickTransformImage возвращает трансформированное изображение как новый ресурс, который должен быть прикреплен к переменной, для того чтобы быть сохраненным. И наоборот, предыдущая функция, которую мы рассмотрели, – MagickCropImage – действовала на ресурсной переменной, которая была передана ей; она возвращает логическое значение (TRUE или FALSE). При написании вашего собственного кода MagickWand убедитесь, что вы подтвердили тип возвращаемого функциями значения, поскольку в результате любого неверного предположения вы рискуете потратить большое количество времени на отлаживание программы.

Допустим, изображение имеет границу толщиной 20 пикселей на левой и правой сторонах, которую вы хотите удалить, но при этом вы не хотите удалять пиксели сверху или снизу изображения. Для этого воспользуйтесь следующим скриптом:

Переформатированное изображение

Рисунок 5: Переформатированное изображение

Далее, предположим, что вы хотите изменить формат изображения с PNG на JPEG. Вот скрипт, который производит конвертирование:

Изображение, конвертированное из формата PNG в формат JPEG

Рисунок 6: Изображение, конвертированное из формата PNG в формат JPEG

Изображения можно вращать. Предположим, вы хотите повернуть рисунок выше на 45 градусов по часовой стрелке. Нет проблем!

Повернутое изображение

Рисунок 7: Повернутое изображение

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

Повернутое изображение с голубым фоном

Рисунок 8: Повернутое изображение с голубым фоном

Достаем кролика из шапки

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

Вы обнаружите еще одно изменение: set time limit устанавливает тайм-аут скрипта в секундах (в данном случае до пяти минут). Это мера предосторожности может быть полезна при условии, что ваш скрипт может обрабатывать изображения, размер которых может превысить установленный по умолчанию тайм-аут скрипта для вашего веб-сервера. Несколько полезных советов

Если вы хотите узнать больше о пакете программ ImageMagick, воспользуйтесь книгой Майкла Стилла (Michael Still) “The Definitive Guide to ImageMagick” (ISBN 1590595904), выпущенной в декабре 2005 года издательством Apress. В ней содержится подробное описание, как установить и конфигурировать ImageMagick дня некоторых дистрибутивов Linux, а также Microsoft Windows. В главах книги вы найдете информацию об основах манипулирования и сжатия изображений, вспомогательных программах ImageMagick, художественной трансформации и других типах трансформации изображений, командах рисования и другие метаданные. В конце книги находятся примеры, в которых ImageMagick используется внутренними программами, написанными на языке Perl, C, Ruby и PHP.

На веб-сайте ImageMagick содержится некоторая документация. Для каждых десяти программ командной строки ImageMagick сайт предлагает страницу, которая кратко объяснит задачу программы, предоставит примеры ее использования и список всех опций командной строки. Для каждой опции существует страница с более подробным описанием. Более того, одна из страниц сайта посвящена доступным интерфейсам прикладного программирования (API) ImageMagick, для 11 различных языков программирования, в том числе PHP, Perl и Java.

Чтобы узнать больше о пакете программ ImageMagick и его командах, загрузите онлайн инструкцию. Она находится в формате HTML Help Compiled. Для imagick как API существует меньше ресурсов, при этом в основном они содержат образец кода из каталога примеров в пределах загружаемого пакета.

Многие программисты и веб-разработчики считают, что изучение работающего кода – это самый эффективный способ изучения новой технологии, и ImageMagick не является исключением. Кодовые фрагменты выше иллюстрируют фундаментальные операции с изображениями. Для того чтобы узнать, как осуществлять более сложные операции, ознакомьтесь с примерами использования ImageMagick Энтони Тиссена (Anthony Thyssen).

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

Понравилась статья?

]]>
janickiy@mail.ru (Alexander) Статьи Thu, 24 Jan 2013 14:10:43 +0000
PHP расширения для работы с MP3 http://janicky.com/stati/php-rasshireniya-dlya-raboty-s-mp3 http://janicky.com/stati/php-rasshireniya-dlya-raboty-s-mp3

Сегодня музыкальные интернет-магазины, как, например Musikload, приобрели большую популярность. В этой статье я расскажу вам о считывании метаинформации mp3 файлов посредством PHP, что позволит вам создавать музыкальные каталоги. Это довольно просто, поддержка базы данных не требуется.

Откуда mp3 плеер знает информацию об исполнителе или названии проигрываемого трека? В этом нет никаких чудес! Эта информация хранится в файлах. Музыкальные файлы других форматов, таких как WMA или Ogg Vorbis, также содержат эту информацию, но в этой статье мы поговорим о формате mp3.

Спецификация mp3 определяет способ хранения музыкальных данных, но не предусматривает возможности сохранения метаданных трека, например названия или имени исполнителя. Чтобы миновать эти ограничения, был создан стандарт ID3. Согласно этой спецификации, метаданные должны быть помещены в ID3-теги. ID3-теги первой версии (ID3v1-Tags) имеют простую конструкцию и пишутся в конце файла. Их размер не должен превышать 128 байтов. Структура тегов следующая: за строковым значением «TAG» должна следовать информация о названии (30 символов), исполнителе (30 символов), альбоме (30 символов), годе выпуска (четырехзначное число), а также комментарий (30 символов) и жанр (1 байт). Тэг с такой структурой выглядит так: ID3v1.0-Tag. Существует еще один формат - ID3v1.1-Tag. Он позволяет хранить информацию о порядковом номере трека.

Для считывания информации с ID3v1-тегов в библиотеку PEAR уже включили пакет MP3_Id[3]. Это позволят извлекать информацию из тега и записывать ее. Листинг 1 показывает, как считывать информацию с тегов. При этом создается объект класса MP3_ID, далее происходит считывание файла, после чего методом getTag() производится извлечение информации. Результаты показаны в Листинге 2.

Листинг 1
read("../data/Little-Big-Man.mp3");

if (PEAR::isError($result)) {
die($result->getMessage() . "\n");
}

// Читаем поля и выволдим информацию
echo "Имя: " . $id3->getTag("name") . "\n";
echo "Исполнитель: " . $id3->getTag("artists") . "\n";
echo "Альбом: " . $id3->getTag("album") . "\n";
echo "Год: " . $id3->getTag("year") . "\n";
echo "Комментарий: " . $id3->getTag("comment") . "\n";
echo "Жанр: " . $id3->getTag("genre") . "\n";
echo "Жанр (номер): " . $id3->getTag("genreno") . "\n";
echo "Трэк: " . $id3->getTag("track") . "\n";

?>

Листинг 1
Имя: Little Big Man
Исполнитель: Dirty Mac
Альбом: Demo-Tape
Год: 2001
Комментарий: Song from the Demo-Tape album
Жанр: Rock
Жанр (номер): 17
Трэк: 5

Листинг 3 показывает, как можно менять содержимое ID3-тегов, а также создавать их. Сначала создается объект класса MP3_ID (так же, как в Листинге 1), затем происходит считывание файла, а после, посредством использования метода setTag($fieldname, $value), в тег помещается нужная информация. Если вы хотите удалить все теги, ознакомьтесь с Листингом 4. Для удаления тегов используйте метод remove().

Листинг 3
read('../data/Little-Big-Man.mp3');

// Ошибка "Tag not found" игнорируется
if (PEAR::isError($result) && $result->getCode() !== PEAR_MP3_ID_TNF) {
die($result->getMessage() . "\n");
}

// Определяем информацию
$id3->setTag('name', 'Neuer Titel');
$id3->setTag('artists', 'Andere Band');
$id3->setTag('album', 'Schlagertraum #3');
$id3->setTag('year', 1984);
$id3->setTag('comment', 'Volksmusikal. Hochgenuss');
$id3->setTag('genre', 'Folk');
$id3->setTag('track', 5);

// Записываем информацию в тег
$result = $id3->write();
if (PEAR::isError($result)) {
die($result->getMessage() . "\n");
}

echo "Тег успешно записан!\n";

?>
Листинг 4
read('../data/Little-Big-Man.mp3');
if (PEAR::isError($err)) {
die($err->getMessage() . "\n");
}

// Удаляем тег
$result = $id3->remove();
if (PEAR::isError($result)) {
die($result->getMessage() . "\n");
}

echo "Тег успешно стерт!\n"; 
?>

Использование PECL

В 2004 году появилось новое PHP расширение - ext/id3[7]. В отличие от MP3_ID эта библиотека написана на языке С, а не PHP, поэтому она должна работать быстрее. Для того чтобы использовать это расширение, следует воспользоваться PEAR-installer или компилировать PHP, включив поддержку этого расширения. Эта библиотека позволяет изменять содержимое ID3-тегов. Для этого вам потребуется всего лишь массив, как в Листинге 6, а также функция id3_set_tag(). Первым параметром данной функции является название mp3 файла. Второй параметр – массив с необходимой информацией. Третий параметр – необязательный. Он представляет собой константу, показывающую версию ID3-тега. В настоящей версии библиотеки функция id3_set_tag() работает только с тегами версии 1.0 и 1.1. В Листинге 7 содержится необходимый код php. В дополнение к этому Листинг 8 показывает, как удалить настоящий тег, используя функцию id3_remove_tag.

Листинг 5
Листинг 6
Array 
( 
[title] => Little Big Man 
[artist] => Dirty Mac 
[album] => Demo-Tape 
[year] => 2001 
[comment] => Song vom Demo-Tape 
[track] => 5 
[genre] => 17 
)

Листинг 7
 'Новое название',
'artist' => 'Другая группа',
'album' => 'Schlagertraum #3',
'year' => 1984,
'genre' => id3_get_genre_id('Rock'),
'comment' => 'Отличная популярная мелодия',
'track' => 5
);

// Записываем тег
$result = id3_set_tag('../data/Little-Big-Man.mp3', $tag, ID3_V1_1 );
if ($result === false) {
echo "Тег не был успешно записан!\n";
}

echo "Тег успешно записан!\n"; 

?>

Новое поколение

Несмотря на то, что использование ID3-тегов позволяет сохранять важную информацию о содержимом mp3 файлов, существует несколько ограничений для версий 1.0 и 1.1:

в связи с фиксированным размером тега ограничен размер сохраняемой информации;

ограничено количество сохраняемых атрибутов.

Для того чтобы устранить эти ограничения, были созданы ID3-теги версии 2[2] - ID3v2. Теги ID3v2 записываются в начале файла. Они могут содержать больше информации, чем ID3v1-теги. Такой информацией может быть информация об авторских правах, BMP или тексте песен. Новые возможности тегов ID3v2 значительно усложнили процесс считывания информации. При исполнении кода из Листинга 9 получится результат, указанный в Листинге 10.

Каждый фрейм ID3v2-тега обладает уникальным ID. Ext/id3 имеет две функции, которые позволяют узнавать содержимое фрейма. Это id3_get_frame_short() и id3_get_frame_long_name(). В качестве параметра они принимают id фрейма и возвращают его описание.

Листинг 8
Листинг 9

Дополнительная информация

Использование библиотеки MP3_Id позволяет не только считывать информацию ID3-тегов, но также получать интересную информацию о самом mp3 файле. Получение данной информации возможно при использовании метода study(), а после, используя метод getTag(), вы можете выбирать необходимую информацию. Листинг 12 показывает, как это работает. Результаты показаны в Листинге 13.

Листинг 10
Array 
( 
[copyright] => Dirty Mac
[originalArtist] => Dirty Mac 
[composer] => Marcus Goetze 
[artist] => Dirty Mac 
[title] => Little Big Man 
[album] => Demo-Tape 
[track] => 5/12 
[genre] => (17)Rock 
[year] => 2001 
)

Листинг 11

Листинг 12
read("../data/Little-Big-Man.mp3"); 


// Ошибки типа "Тег не найден" игнорируются
if (PEAR::isError($result) && $result->getCode() !== PEAR_MP3_ID_TNF) { 
die($result->getMessage() . "\n"); 
} 
$result = $id3->study();
if (PEAR::isError($result)) { 
die($result->getMessage() . "\n"); 
} 

echo "MPEG " . $id3->getTag("mpeg_ver") . " Layer " . $id3->getTag("layer") . "\n"; 
echo $id3->getTag("mode"). "\n"; 
echo "Размер файла: " . $id3->getTag("filesize") . " Bytes\n";
echo "Качество: " . $id3->getTag("bitrate") . "kB/s n";
echo "Продолжительность: " . $id3->getTag("length") . " min\n"; 
echo "Частота оцифровки: " . $id3->getTag("frequency") . "Hz\n"; 

?>

Листинг 13
MPEG 1 Layer 3 
Joint Stereo 
Размер: 4089856 Bytes 
Качество: 128kB/s 
Продолжительность: 04:15 min 
Частота оцифровки: 44100Hz

Понравилась статья?

]]>
janickiy@mail.ru (Alexander) Статьи Thu, 24 Jan 2013 14:09:11 +0000
Использование дескрипторов файлов для работы с файлами в Perl http://janicky.com/stati/ispolzovanie-deskriptorov-failov-dlya-raboty-s-failami-v-perl http://janicky.com/stati/ispolzovanie-deskriptorov-failov-dlya-raboty-s-failami-v-perl

Perl имеет доступ к тем же основным, помогающим управлять исполнением программ дескрипторам файлов, а именно как: STDIN, STDOUT и STDERR. Более того, возможности для работы с дескрипторами файлов, которые указывают на реальные файлы, в Perl очень обширны и позволяют делать так, чтобы программы обрабатывали файлы любым необходимым образом. С помощью дескрипторов файлов можно открыть файл, передать его в массив, записать информацию в новый файл или даже выполнить все эти операции сразу со многими файлами одновременно.

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

while (<>) 
{ 
  print $_;
}

Затем запустите свою программу, указав одно или более имен файлов в командной строке:

# ./myscript.pl filel.txt file2.txt

Это приведет к распечатке содержимого всех указанных файлов, почти так же, как и при использовании команды cat. Такой способ получения доступа к содержимому файлов является удобным и быстрым. Однако он также и достаточно ограниченный; ромбическая операция в принципе представляет собой "вырожденный вариант" истинного дескриптора файла. Давайте рассмотрим несколько заданных должным образом дескрипторов, чтобы увидеть, что они на самом деле могут делать.

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

open (FH,"/path/to/filel.txt");
while ($thisline = )
{
  chomp ($thisline);
  print "$i: $thisline\n";
} 
close (FH);

Бывает так, что Perl не удается открыть файл, либо потому что он не существует, либо потому что установленные полномочия не разрешают выполнять чтение этого файла, либо еще по какой-то причине. Вы можете перехватить подобные события, воспользовавшись операцией die: если при вычислении выражения управление перейдет к die, он передаст свой аргумент (если таковой имеется) на стандартный вывод и выполнение сценария завершится. Ниже показан наиболее распространенный способ применения операции die при открытии файлов:

open (FH,"/path/to/filel. txt") || die ("Невозможно открыть filel.txt!");

Выполнение записи в файлы является немного более сложной задачей, поточу что существует так много различных способов того, как ее можно выполнить, Главное, запомните, что для записи можно применять любой дескриптор, который разрешается использовать в командной строке, такой как > (перезапись) или >>(добавление), или даже | (конвейер). Последний может пригодиться, скажем, для того, чтобы сценарий записывал свой вывод в электронное сообщение (обратите внимание на упрощенный метод прохода через массив @contents и распечатки каждой строки):

open (FH,">/path/to/file2.txt"); 
print FH $_ foreach (@contents); 
close (FH);

open (MAIL,"| /usr/sbin/sendmail -oi -t"); 
print MAIL "From: me\@somewhere.com\n"; 
print MAIL "To: you\@somewhereelse.com\n"; 
print MAIL "Subject: Важная информация!\n\n"; 
print MAIL $_ foreach (@contents);
close (MAIL);

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

):

select(FH);

В таком случае вам не придется все время вводить print FH. Однако вам обязательно нужно будет изменить дескриптор обратно ка STDOUT. когда вы закончите работать с FH.

Для работы с каталогами доступны свои функции: opendir () и readdir (); вы можете открыть каталог и прочитать его содержимое в массив следующим образом:

opendir (DIR,"/path/to/dir"); 
@files = sort readdir  (DIR); 
closedir  (DIR);

Даже с помощью всего лишь описанных методов вы уже можете делать некоторые очень интересные вещи. Например, вы можете открыть файл /etc/passwd, выбрать оттуда все записи с идентификатором пользователя (UID) больше 1000 и распечатать регистрационные и обычные имена таких пользователей:

#!/usr/bin/perl

open (PASSWD,"/etc/passwd") || die ("Невозможно открыть файл passwd!");
while($line = @passwd)
{  
   @userdata = split(/:/,$line);  
   if($userdata[2] > 1000) 
   {     
      print "$userdata[0]: $userdata[4]\n";
   }
}

Вот и готова полезная программа! Именно это и делает Perl таким популярным. Он позволяет создавать программы, затрачивая лишь минимальное количество усилий, что значительно упрощает жизнь.

Понравилась статья?

]]>
janickiy@mail.ru (Alexander) Статьи Thu, 24 Jan 2013 14:04:53 +0000