БлогNot. PHP: сервис одним файлом

Помощь дата->рейтинг Поиск Почта RSS канал Статистика nickolay.info Домой

PHP: сервис одним файлом

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

1. Форма + текст

Если речь идёт о Web-приложении, которое должно выдавать результаты "текстом" и на ту же страницу, с которой вводились данные формы, удобной представляется следующая организация скрипта (листинг):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
 <meta content="text/html; charset=Windows-1251" http-equiv="content-type">
 <title>Заголовок страницы</title>
</head>
<body>

<?php
 //Блок 0 - пара функций для безопасной обработки данных
 function trimall($string) { return trim(preg_replace("/\s+/"," ",$string)); }
 
 function magic ($path) {
  @ini_set('magic_quotes_runtime', '0'); @ini_set('magic_quotes_sybase', '0');
  if (@get_magic_quotes_gpc()=='1') $path=stripslashes($path); //magic_quotes_gpc не меняется программно - см. доки
  return $path;
 }
 
 //Блок 1 - обработка разрешённых скрипту параметров
 $params = array ('name','gender','education','php','cpp','java','text','action');
 //список разрешенных в скрипте параметров, все переменные создадутся автоматически из данных $_POST/$_GET или пустыми
 while (list($num,$var) = each($params)) {
  if (!empty($_POST[$var])) $$var = trimall(htmlspecialchars(magic($_POST[$var])));
  else if (!empty($_GET[$var])) $$var = trimall(htmlspecialchars(magic($_GET[$var])));
  else $$var = '';
 }
 
 //Блок 2 - вывод и заполнение формы 
 echo '
 <form name="f1" method="post" action="'.$_SERVER['PHP_SELF'].'">
  <table align="center" border="0" cellpadding="4" cellspacing="0" width="90%">
   <caption>Пример формы с обработкой и сохранением ввода после отправки</caption>
   <tr>
    <td>Имя:</td>
    <td>
     <input type="text" name="name" maxlength="40" size="40" value="'.$name.'">
    </td>
   </tr>
   <tr>
    <td>Пол:</td>
    <td>
     <input name="gender" value="m" type="radio" '.($gender=='m'?'checked':'').'>Мужской
     <input name="gender" value="f" type="radio" '.($gender=='f'?'checked':'').'>Женский
    </td>
   </tr>
   <tr>
    <td>Образование:</td>
    <td>
     <select name="education" size="1">';
 $select_values = array ('none'=>'Не выбрано','middle'=>'Среднее или ниже',
  'high'=>'Высшее или ученая степень'); //Возможные значения списка => подписи
 foreach ($select_values as $key=>$value) {
  echo '<option value="'.$key.'"'.($education==$key?' selected':'').'>'.$value;
 }
 echo '
     </select>
    </td>
   </tr>
   <tr>
    <td>Какие языки программирования Вы знаете:</td>
    <td>';
 $checkbox_values = array ('php'=>'PHP','cpp'=>'C++','java'=>'Java'); //Переменные флажков => подписи	 
 foreach ($checkbox_values as $key=>$value) {
  echo '<input type="checkbox" name="'.$key.'" value="1"'.($$key==1?' checked':'').'>'.$value;
 }	  
 echo '
    </td>
   </tr>
   <tr>
    <td>Ваш комментарий:</td>
    <td>
     <textarea name="text" rows="6" cols="72">'.(!empty($text)?"$text":'').'</textarea>
    </td>
   </tr>
   <tr>
    <td>&nbsp;</td>
    <td>
     <input type="submit" name="action" value="Отправить"> 
     <input type="reset" value="Отмена">
    </td>
   </tr>
  </table>
 </form>';

 //Блок 3 - расчёт и вывод результатов
 if (!empty($action)) { 
  //Здесь обаботка данных и вывод результатов обработки
  echo 'Имя="'.$name.'"<br>'.
   'Пол="'.$gender.'"<br>'.
   'Образование="'.$education.'"<br>'.
   'PHP="'.$php.'"<br>'.
   'C++="'.$cpp.'"<br>'.
   'Java="'.$java.'"<br>'.
   'Текст=<br>'.nl2br($text);
 }
?>
</body></html>

Здесь я сознательно использовал все основные интерфейсные элементы классического HTML4, чтобы показать, как в них передавать данные "с сохранением" предыдущего ввода.

Этот код сохраняет заполненную часть формы, "чистит" данные от лишних разделителей (функция trimall), убирает внедрённую в данные разметку (htmlspecialchars) и решает php-шные проблемы с кавычками (magic).

Обработчиком формы назначен текущий файл, как бы он ни назывался (указание $_SERVER['PHP_SELF'])

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

Мне кажется, это в данном случае лучше, чем писать просто HTML вне тега <?php ... ?> и потом делать кучу PHP-вставок для подстановки значений в форму.

Разрешены и GET, и POST. Также обратите внимание, как выглядят списки $select_values и $checkbox_values, применяемые для программного создания нескольких элементов списка и группы радиокнопок.

Если на странице результатов не должна отображаться форма, возьмите блоки 2 и 3 в единый условный оператор, например, так:

if (empty($action)) { 
 //Блок 2
}
else {
 //Блок 3
}

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

echo '<form name="f2" method="post" action="'.$_SERVER['PHP_SELF'].'">';
foreach ($params as $p) if ($p!='action') echo '<input type="hidden" name="'.$p.'" value="'.$$p.'">';
echo '<input type="submit" name="back" value="Назад"> ';
echo '</form>';

Здесь не возвращается параметр action (от кнопки), так как именно по его наличию в данных мы судим, нужно выводить форму или результат.

Если результаты должны открываться в новом окне (вкладке) браузера, просто добавьте в открывающей части тега первой формы стандартный атрибут target:

<form name="f1" method="post" target="_blank" action="'.$_SERVER['PHP_SELF'].'">

Разумеется, есть и другие альтернативы, например, вывести текст с помощью яваскрипта (или яваскрипт-библиотеки вроде JQuery) в заранее созданный раздел <div>. Но для этого надо быть уверенным, что яваскрипт у пользователя включён :)

Ну и PHP-фреймворков тоже хватает, только вот и скорость приложения, и скорость разработки окажутся ниже...

 Посмотреть этот скрипт в работе

 Скачать архив ZIP с этим примером на PHP (2 Кб)

2. Форма + графика

При работе с графикой принцип организации скрипта меняется не сильно. Основное отличие - заголовки HTML-документа надо создавать только для страницы с формой, а результат выдаётся в виде картинки, так что там применяется директива header ('Content-Type: image/gif');

Точно так же скрипт может выводить картинку-результат в текущее окно или в новое. Но для случая текущего окна мы не сможем добавить кнопку-форму для возврата к набранным данным, ведь мы передаём другой тип содержимого (картинку GIF).

Так как подобного готового сервиса под рукой не нашлось, написал маленькую "рисовалку узоров". Она похожа на этот сервис, опишу параметры, разрешённые в адресе URL:

Размер картинки определяется автоматически, но не может превышать 1000 пикселов. Картинка всегда квадратная.

Полный листинг скрипта приводится ниже:

<?php
if (!isset($_GET['submit'])) {
 echo '
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html>
  <head>
   <meta content="text/html; charset=Windows-1251" http-equiv="content-type">
   <title>Rounder</title>
  </head>
  <body>
  <form method="get" action="'.$_SERVER['PHP_SELF'].'" target="_blank">
  <table border="0">
   <tr>
    <td><p>Порядок рекурсии</p></td>
    <td>
     <select name="n" size="1">
      <option value="1">1
      <option value="2">2
      <option value="3" selected>3
      <option value="4">4
      <option value="5">5
      <option value="6">6
      <option value="7">7
      <option value="8">8
      <option value="9">9
     </select>
    </td>
   </tr>
   <tr>
    <td><p>Начальный радиус, пикселов</p></td>
    <td>
     <select name="r" size="1">
      <option value="50">50
      <option value="100" selected>100
      <option value="200">200
      <option value="300">300
      <option value="400">400
      <option value="500">500
     </select>
    </td>
   </tr>
   <tr>
    <td><p>Цвет фона RRGGBB (-1 = прозрачный)</p></td>
    <td>
     <input type="text" name="back" value="-1" size="6" maxlength="6">
    </td>
   </tr>
   <tr>
    <td><p>Цвет линий RRGGBB</p></td>
    <td>
     <input type="text" name="lines" value="FF0000" size="6" maxlength="6">
    </td>
   </tr>
   <tr>
    <td><p><small>Сторона картинки - до 1000 пикселов, время выполнения - до 15 сек.</small></p></td>
    <td>
     <input type="submit" name="submit" value="OK">
    </td>
   </tr>
  </table>
  </form>
  </body></html>
 ';
 exit(0);
}

set_time_limit (15); //Лимит времени выполнения

function Circle($img,$color,$x,$y,$r,$n) {
 if ($n>=0) {
  imageellipse ($img,$x,$y,$r<<1,$r<<1,$color);
  Circle($img,$color,$x+$r,$y,round($r/2),$n-1);
  Circle($img,$color,$x,$y-$r,round($r/2),$n-1);
  Circle($img,$color,$x-$r,$y,round($r/2),$n-1);
  Circle($img,$color,$x,$y+$r,round($r/2),$n-1);
 }
}

//Обработка параметров
function get_rgb_from_hex ($hex) { //Цвет RRGGBB (Hex) в массив (r,g,b) десятичные
 $rgb=array();
 for ($i=0; $i<6; $i+=2) $rgb[]=hexdec(substr($hex,$i,2));
 return $rgb;
}

$params = array ('n','r','back','lines');
while (list($num,$var) = each($params)) {
 if (!empty($_GET[$var])) $$var = intval($_GET[$var]);
 else $$var=0;
}

if ($n<1) $n=3; // Порядок рекурсии
if ($r<10 or $r>500) $r=100; // Начальный радиус 10-500
$width = 0; $pow2n = 1;
for ($i=0; $i<=$n; $i++) { $width+=round($r/$pow2n); $pow2n<<=1; }
$width=$width*2+8;
if ($width>1000) $width=1000; // Размер стороны картинки обрезается до 1000 пикселов

$transparent=false; //Прозрачность
$rback=$gback=$bback=255;
if (isset($_GET['back'])) { //Цвет фона RRGGBB, если меньше 0 - прозрачный
 $back=htmlspecialchars(trim($_GET['back']));
 if (preg_match("#^[0-9A-Fa-f]{6}$#",$back)) list ($rback,$gback,$bback) = get_rgb_from_hex ($back);
 else if (intval($back)<0) $transparent=true;
}
$rlines=255; $glines=$blines=0;
if (isset($_GET['lines'])) { //Цвет линий RRGGBB
 $lines=htmlspecialchars(trim($_GET['lines']));
 if (preg_match("#^[0-9A-Fa-f]{6}$#",$lines)) list ($rlines,$glines,$blines) = get_rgb_from_hex ($lines);
}

//Отрисовка
if (!extension_loaded('gd')) die('Cannot initialize GD library');
$img = @imagecreatetruecolor($width, $width) or die ('Cannot initialize new GD image stream');
$back = imagecolorallocate($img,$rback,$gback,$bback); 
$lines = imagecolorallocate($img,$rlines,$glines,$blines);
imagefilledrectangle ($img, 0, 0, $width, $width, $back);
if ($transparent) imagecolortransparent($img, $back);
Circle($img,$lines,round($width/2),round($width/2),$r,$n);

//Вывод
header ('Content-Type: image/gif');
imagepng ($img);
imagedestroy($img);
?>

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

 Посмотреть этот скрипт в работе

 Скачать архив ZIP с этим примером на PHP (2 Кб)


теги: программирование сервис php

комментарии (0)

07.06.2013, 16:31; рейтинг: 10573

  в началопоиск по блогунаписать авторустатистика

Наверх Яндекс.Метрика
© PerS
вход