БлогNot. Самые маленькие полезные скрипты на PHP

Самые маленькие полезные скрипты на PHP

сейчас в списке: 57 скриптов Удивительно, что такие "базовые" вопросы вообще задают, уже якобы изучив весь PHP вплоть до классов и шаблонов... но ведь задают :)

Вероятно, эта заметка ещё будет пополняться примерами очень маленьких, но полезных скриптов на PHP. Об установке программного обеспечения, нужного для работы с PHP, написано в этой статье (Denwer) или лучше вот в этой, более новой (XAMPP).

Скрипты проверялись на локальном хосте в актуальных на момент добавления того или иного примера версиях PHP 5, а позднее 7 или 8.

Для поиска на странице нужных слов нажмите в браузере комбинацию клавиш Ctrl+F и введите или вставьте слова в окно поиска.

1. Как посмотреть все настройки PHP на моём сервере?

Выполнить на нём следующий файл:

<?php
 phpinfo();
?>

2. А как посмотреть все серверные переменные?

Выполните на сервере этот скрипт:

<?php
 foreach ($_SERVER as $k=>$v) echo "\n<br><b>$k=</b>".$v;
?>

3. Можно ли не писать отдельно обработку для данных формы, переданных методами GET и POST?

Напишите её для массива $_REQUEST. Он ещё и cookies включает.

<?php
 function get_param ($name,$number=0) { 
  //имя параметра $name и пометка $number, числовой ли он
  if (isset($_REQUEST[$name])) { //массив $_REQUEST = $_POST+$_GET+$_COOKIE !
   $name = trim(htmlspecialchars($_REQUEST[$name],ENT_QUOTES,'UTF-8')); 
   //делать для всех типов параметров
   return ($number ? doubleval($name) : $name);
  }
  else return ($number ? 0 : ""); 
 }

 $go = get_param('go'); //строковый параметр, обозначающий "действие" скрипта
 $num = get_param('num',1); //числовой параметр
 echo "$go,$num";
?>

4. Как вывести сегодняшний день недели по-русски, стандартная функция date не понимает локали?

<?php
 $w = Array('Вс','Пн','Вт','Ср','Чт','Пт','Сб');
 echo $w[date('w')];
?>

5. Как показать текущие дату и время на сервере?

<?php
 echo date('d.m.Y, H:i');
?>

6. Как определить IP-адрес посетителя?

<?php
 echo getenv('REMOTE_ADDR');
?>

Это в простейшем случае. А более грамотно - как вот тут в function get_ip.

7. Как генерировать случайные числа?

Если целые в заданных пределах, например, от 1 до 100 включительно, то

<?php
 echo rand(1,100);
?>

8. А если нужны вещественные случайные числа?

<?php
 echo mt_rand() / mt_getrandmax();
?>

Получим вещественные равномерно распределённые числа от 0 до 1. Ну а масштабировать в любой другой диапазон легко, например, в [-5;5]:

<?php
 $a0 = mt_rand() / mt_getrandmax();
 $min = -5;
 $max = 5;
 $a = $min + $a0*($max-$min);
 echo $a;
?>

9. Как отсканировать папку на сервере?

<?php
 $array = scandir('.');
 //здесь сканируется текущая папка (ссылка на неё - одной точкой)
 echo '<pre>';
 print_r($array);
 echo '</pre>';
?>

10. Как узнать имя файла скрипта? Как узнать размер файла?

2 ответа в одной строке :)

<?php
 echo filesize($_SERVER['SCRIPT_FILENAME']).' байт';
?>

11. Как скачать файл скриптом?

<?php
 $filename = 'data.zip';  //имя файла для скачивания
 $filefolder = 'folder/'; //имя папки
 $filesize = filesize($filefolder.$filename);
 header('HTTP/1.1 200 OK');
 header('Connection: close');
 header('Content-Type: application/octet-stream');
 header('Accept-Ranges: bytes');
 header('Content-Disposition: attachment; filename='.$filename);
 header('Content-Length: '.$filesize);
 readfile($filefolder.$filename);
?>

Здесь скачивается файл data.zip из папки на сервере folder, но пользователь не видит пути к файлу. В нашем случае для домена domain.com это путь http://domain.com/folder/file.zip

Также не стоит забывать о возможности защиты папок от просмотра с помощью файла .htaccess

12. Как отобразить чужой сайт/документ?

<?php
 echo file_get_contents('http://google.com');
?>

А если нужно загрузить чужой сайт в отдельный фрейм?

<?php 
 $url = 'http://www.anekdot.ru';
 $html =  file_get_contents($url) or die ('Ошибка получения данных с '.$url);
 echo '<iframe width="640" height="480" srcdoc="'.htmlentities($html,ENT_QUOTES,'UTF-8').'"></iframe>';
?> 

(здесь предполагается, что документ загружен по протоколу http:// и применяется кодировка Юникода UTF-8).

13. Как показать пользователю адрес своего сайта?

<?php
 echo 'Вы находитесь на сайте '.$_SERVER['HTTP_HOST'];
?>

Если нужен полный URL выполняемого скрипта, то можно так:

<?php
 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') $link = "https"; 
 else $link = "http"; 
 $link .= "://"; 
 $link .= $_SERVER['HTTP_HOST']; 
 $link .= $_SERVER['REQUEST_URI']; 
 echo $link; 
?>

14. Как случайно "перемешать" элементы массива?

Для этой цели, как и для многих других типовых действий с массивами, в PHP есть готовые функции.

<?php
 $items = array (1,2,3,4,5);
 shuffle ($items);
 print_r ($items);
?>

15. Как получить/изменить время доступа или модификации файла?

<?php
$filename = 'input.txt';
$mtime = filemtime($filename); //получить время изменения файла
touch($filename,
      time(), //установить время изменения в текущее
      fileatime($filename)); //оставить время доступа неизменным
?>

Существенно, что touch создаст файл, если он не существует.

16. Как сделать замену (модификацию) строк во множестве текстовых файлов?

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

<?php
foreach (glob("./*.txt") as $filename) {
 $file = file_get_contents($filename);
 file_put_contents ($filename, 
  preg_replace_callback("/([a-zA-Z]+)/",
                        function ($matches) { return strtoupper($matches[0]); },
                        $file));
}
?>

Здесь мы делаем большими все латинские буквы в файлах *.txt из текущей папки скрипта.

17. Как прочитать содержимое файла построчно?

<?php
$file = fopen(__FILE__, 'r');
while ($line = fgets($file)) {
    $line = rtrim($line);
    echo htmlspecialchars($line)."<br>\n";
}
?>

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

<?php
$file = fopen('input.txt', 'r');
while (!feof($file)) { 
 $line = rtrim(fgets($file));
 if ($line) echo (htmlspecialchars($line)."<br>\n");
}
?>

При этом выводе мы дополнительно игнорируем пустые строки.

18. Как переименовать файл?

<?php
 rename('input.txt', 'output.txt');
?>

Ну и другие типовые файловые операции похожи на C/C++.

19. Как безопасно создать временный файл с уникальным именем?

<?php
 $f = tmpfile();
 //работа с файлом $f:
 fwrite ($f, 'abracadabra');
 fseek ($f, 0);
 echo fread ($f, 1024);
 fclose($f); //будет удалён при закрытии
?>

20. Как избавиться от лишних пустых строк в тексте?

<?php
 function removeEmptyLines ($s) {
  return preg_replace ("/(^[\r\n]*|[\r\n]+)[\s]*[\r\n\s]+/mu","\n",trim($s));
 }

 $s = 
 "   За мусор       енный


     \t
 т


екст\r\n\r\n";
 echo '<pre>'.removeEmptyLines($s).'</pre>';
?>

В этом и следующем примере регулярное выражение предполагает, что для скрипта использована кодировка Юникода UTF-8.

21. А как удалить из строки или текста все лишние разделители, в том числе, между словами?

<?php
function trimall ($string) { 
  return preg_replace("/\s+/"," ",trim($string));
 }
 $s = 
 "   За мусор       енный


     \t
 т


екст\r\n\r\n";
 echo '<pre>'.trimall($s).'</pre>';
?>

Обратите внимание, что этот код также "вытянет" изначально многострочный текст в одну строку, иногда это удобно.

22. Как выбрать из массива случайный элемент?

<?php
 $arr = Array (1,2,3);
 echo $arr[array_rand($arr)];
?>

23. Как оставить от строки только буквы (латинские и русские)?

<?php
 function keepLettersOnly ($s) { //Оставить ТОЛЬКО БУКВЫ
  return preg_replace("/[^а-яёa-z]/mui","",$s);
 }
 $s = "  За мусор\t 
     
енный! \t  \n\n\n    текст hello, world!";
 echo '<pre>'.keepLettersOnly($s).'</pre>';
?> 

Здесь также предполагается, что мы работаем с кодировкой Юникода UTF-8.

24. Как оставить в массиве только элементы, отвечающие какому-либо условию?

Поможет функция array_filter, в которую передана callback-функция, осуществляющая отбор (но не редактирование!) нужных элементов.

<?php
 $arr = array (1,-2,3,4,0);
 $arr1 = array_filter ($arr, function ($item) { return $item%2==0; });
 print_r ($arr1); //только чётные элементы
 $arr2 = array_filter ($arr, function ($item) { return $item>0; });
 echo '<br>'; print_r ($arr2); //только положительные элементы
?>

25. Как отобразить и отформатировать текущие дату и время, учитывая нужный часовой пояс?

Основные ответы даёт вот этот маленький скрипт, проверенный на XAMPP с PHP 7.

<?php
 setlocale(LC_ALL, 'ru_RU', 'ru_RU.UTF-8', 'ru', 'russian');  
  //Пробуем возможные локали, см.
  // https://www.php.net/manual/ru/function.setlocale.php
 date_default_timezone_set ('Asia/Novosibirsk');
  //Установите свой часовой пояс, список см. на
  // https://www.php.net/manual/ru/timezones.php
 echo time().'<br>'; //Секунды с начала эпохи Unix
 echo microtime().'<br>'; //Формат с микросекундами с начала эпохи Unix ($msec $sec)
 echo date('D M j H:i:s Y').'<br>';  //Отформатированные дата/время
  //Форматы см. на https://www.php.net/manual/ru/function.date.php
echo date('c').'<br>';  //Формат ISO 8601
echo date('r').'<br>';  //Формат RFC 2822
echo date(DATE_RSS).'<br>';  //Формат RSS. Константы форматов см. на
  // https://www.php.net/manual/ru/class.datetimeinterface.php#datetime.constants.types
echo iconv('Windows-1251', 'UTF-8', strftime('%A, %d %h %Y, %H:%M:%S', time())).'<br>';
 //Под Windows всё равно пришлось вызывать iconv
 //Форматы strftime см. на https://www.php.net/manual/ru/function.strftime.php
?>
1579410514
0.58700900 1579410514
Sun Jan 19 12:08:34 2020
2020-01-19T12:08:34+07:00
Sun, 19 Jan 2020 12:08:34 +0700
Sun, 19 Jan 2020 12:08:34 +0700
воскресенье, 19 янв 2020, 12:08:34

26. Как сделать из строки PHP строку JavaScript, сохраняя переводы строк?

Код ниже выводит строку PHP $s в документ и в окно сообщения JavaScript.

<?php
 function make_js_string($s) {
  $arr = explode("\n",$s);
  $res='';
  $cnt = count($arr);
  for ($i = 0; $i < $cnt; $i++) 
   $res .= "'".trim($arr[$i]).($i < $cnt-1 ? "\\n" : '')."'".($i < $cnt-1 ? "+\n" : '');
  return $res;
 }

 $s = " Текст
 с 

 разрывами     
 строк";
 $r = make_js_string($s);
 echo '<pre>'.$r.'</pre>';
 echo '<script>alert('.$r.');</script>';
?>

27. Как сжать на PHP содержимое HTML, убрав лишние разделители и комментарии?

<?php 
 function minimizeHTML ($code) { 
  $search = [
   '/\>[^\S]+/s', //разделители после тегов
   '/[^\S]+\</s', //разделители перед тегами
   '/(\s)+/s', //повторяющиеся разделители
   '/<!--(.|\s)*?-->/' //комментарии HTML
  ]; 
  $replace = array('>', '<', '\\1', ''); 
  return preg_replace ($search, $replace, $code); ; 
 } 

 $html = '<!DOCTYPE    html> 
<html lang="ru"> 
   
<head>  <!-- title of page --> 
   
<title>Демо  страничка  </title> 
   
</head> 
   
   <body> 
   
<!-- body of page --> 
   
<h1>Заголовок</h1> 
Содержимое,слова слова    слова</body>   </html> ';

echo '<textarea rows="10" cols="80">'.minimizeHTML($html).'</textarea>';   
?>

28. Как реализовать авторизацию с функцией "оставаться в системе"?

В блоге есть другие материалы по теме! Здесь показано типовое решение с помощью сессии и cookie-файла. Предполагаем, что используется база данных MySQLi. Предполагается, что пароль хранится зашифрованным стандартной функцией md5. Таблица users может быть устроена как в этой заметке.

<?php 
 session_start(); 
 $my_name = '10.php'; //имя файла скрипта, указать своё
 if (isset($_GET["logout"])) { //выход
  if (isset($_COOKIE["user_login"])) setcookie("user_login", "", time() - 1000); 
  if (isset($_COOKIE["user_password"])) setcookie("user_password", "", time() - 1000); 
  if (isset($_SESSION["name"])) unset($_SESSION["name"]); 
  header ("Location: $my_name");
  exit;
 }
 $name = $password = '';
 $connect = mysqli_connect("localhost", "root", "", "guestbook"); 
  //указать правильные хост, логин, пароль, таблицу
 if (!isset($_SESSION['name'])) { //не авторизован
  if (!empty($_COOKIE['user_login']) and !empty($_COOKIE['user_password'])) { //есть куки
   $name = $_COOKIE['user_login'];
   $password = $_COOKIE['user_password'];
  }
  else if (!empty($_POST["user_name"]) and !empty($_POST["user_password"])) { //присланы данные из формы
   $name = mysqli_real_escape_string($connect, $_POST["user_name"]); 
   $password = md5(mysqli_real_escape_string($connect, $_POST["user_password"])); 
  }
  else { //нет данных о входе
   echo '<p>Введите логин и пароль:</p>
    <form action="'.$my_name.'" method="post">
     <p>Логин: <input type="text" size="20" maxlength="18" name="user_name"></p>
     <p>Пароль: <input type="password" size="20" maxlength="18" name="user_password"></p>
     <p><input type="checkbox" id="remember_me" name="remember_me">
     <label for="remember_me">Запомнить меня</label></p>
     <p><input type="submit" name="login" value="Вход"></p>
    </form>';
   exit;
  }
  $sql = "select * from users where login='" . $name . "' and password='" . $password . "'"; 
   //проверить в запросе имя таблицы (users) и полей (login, password)
  $result = mysqli_query ($connect, $sql); 
  if (!$result) { echo "Неверные логин или пароль"; exit; }
  $user = mysqli_fetch_array ($result); 
  if (!$user) { echo "Неверные логин или пароль"; exit; }
  else {
   if (!empty($_POST["remember_me"])) { 
    setcookie("user_login", $name, time() + (1 * 365 * 24 * 60 * 60)); //Сохранить на 1 год
    setcookie("user_password", $password, time() + (1 * 365 * 24 * 60 * 60)); 
   } 
   $_SESSION["name"] = $name; 
   header ("Location: $my_name"); 
   exit;
  } 
 }
 echo "Вы вошли в систему. <a href=\"$my_name?logout\">Выйти</a>";
?> 

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

Можно по аналогии с JavaScript.

<?php 
function isMobileDevice() { 
 return preg_match(
  "/(android|avantgo|blackberry|bolt|boost|cricket|docomo|fone|hiptop|
   mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i", 
  $_SERVER["HTTP_USER_AGENT"]); 
} 

echo (isMobileDevice() ? "Да" : "Нет");
?> 

30. Как "отдать" пользователю файл .pdf?

Код показан ниже, предполагается, что в папке скипта доступен файл demo.pdf. В отличие от вопроса 11, отдаём файл "порциями".

<?php 
 echo '<a href="'.$_SERVER['PHP_SELF'].'?file=demo" target="_blank">Скачать в новой вкладке</a>';
 if (isset($_GET["file"])) {
  $file = $_GET["file"] .'.pdf'; 
  header("Content-Type: application/octet-stream"); 
  header("Content-Disposition: attachment; filename=" . urlencode($file));    
  header("Content-Type: application/download"); 
  header("Content-Description: File Transfer");             
  header("Content-Length: " . filesize($file)); 
  flush();
  $fp = fopen($file, "r"); 
  while (!feof($fp)) { 
   echo fread($fp, 65536); 
   flush(); //Так как могут быть большие файлы
  }  
  fclose($fp);  
 }
?> 

31. Как определить страну и регион посетителя по IP?

Если не использовать собственных баз данных, поможет ресурс geoPlugin:

<?php 
function get_ip() { 
 if (!empty($_SERVER['HTTP_CLIENT_IP'])) return $_SERVER['HTTP_CLIENT_IP']; 
 else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) return $_SERVER['HTTP_X_FORWARDED_FOR']; 
 else return $_SERVER['REMOTE_ADDR']; 
}
  
$ip = get_ip(); 
echo 'IP-адрес: ' . $ip . '<br>'; 
$file =  file_get_contents("http://www.geoplugin.net/json.gp?ip=".$ip);
if ($file === false) {
 echo 'Ошибка получения данных geoplugin.net!'; exit;
}
$ipdat = json_decode($file);
if (!$ipdat) {
  echo 'Ошибка интерпретации данных geoplugin.net!'; exit;
}
echo 'Континент: ' . $ipdat->geoplugin_continentName . '<br>'; 
echo 'Страна: ' . $ipdat->geoplugin_countryName . '<br>'; 
echo 'Город: ' . $ipdat->geoplugin_city . '<br>'; 
echo 'Широта: ' . $ipdat->geoplugin_latitude . '<br>'; 
echo 'Долгота: ' . $ipdat->geoplugin_longitude . '<br>'; 
echo 'Символ валюты: ' . $ipdat->geoplugin_currencySymbol . '<br>'; 
echo 'Код валюты: ' . $ipdat->geoplugin_currencyCode . '<br>'; 
echo 'Часовой пояс: ' . $ipdat->geoplugin_timezone; 
?> 

На локальном хосте localhost функция get_ip вернёт значение ::1

Чтобы получить публичный IP-адрес компьютера, этот скрипт нужно выполнять на удалённом хосте.

32. Как сгенерировать QR-код для строки?

Хорошая бесплатная библиотека с открытым исходным кодом есть вот тут. Достаточно скачать архив .zip, развернуть его, не создавая новой папки и поместить эту папку в качестве вложенной по отношению к папке расположения скрипта. Скрипт в простейшем случае может быть таким:

<?php
 include 'phpqrcode/qrlib.php'; 
 $text = "blog.kislenko.net"; 
 QRcode::png($text); 
?>

33. Как простым способом проверить, существует ли URL-адрес?

<?php 
 $url = "https://google.com/"; 
  
 $headers = @get_headers($url); 
 if ($headers === false) {
  echo 'Не могу получить заголовки '.$url; exit;
 }
 if (strpos( $headers[0], '404')) echo '404 - URL '.$url.' не существует'; 
 else echo 'URL '.$url.' существует'; 
?> 

34. Как получить MAC-адрес клиента?

<?php 
 $MAC = exec('getmac'); 
 $MAC = strtok($MAC, ' '); 
 echo 'MAC-адрес клиента: '. $MAC; 
?> 

35. Есть ли в PHP структуры данных?

А зачем? Там array правильный :) Впрочем, если хотите возиться с расширениями, для PHP7 есть php-ds

<?php
 $struct = [];
 $struct[0] = 'I\'m string item with number key';
 $struct['value'] = 2; //number item with string key
 var_dump($struct);
?>

Вывод этого примера:

array(2) { [0]=> string(31) "I'm string item with number key" ["value"]=> int(2) } 

36. Как проверить валидность (корректность) адреса E-mail?

В современных версиях PHP лучше не составлять регулярные выражения, а воспользоваться методом filter_var.

<?php
 $test = [
  "admin@dot.com.ru", //+
  "www.dot.com", //-
  "www@ru", //-
  "super-bob@i.edu", //+
  "маша@магазин.рф" //+, но скажет -
 ];
  
 for ($i=0; $i<count($test); $i++) {
  echo $test[$i].': '.(filter_var($test[$i],FILTER_VALIDATE_EMAIL)?'+':'-').'<br>';
 }
?>

При этом нужно понимать, что кириллические и другие не-латинские домены метод воспринимать не будет, если они нужны, то помогут как раз регулярные выражения.

<?php
 $test = [
  "Admin@dot.com.museum", //+
  "www.dot.com", //-
  "www@ru", //-
  "super-bob@i.edu", //+
  "маша@магазин.рф" //+
 ];

 function isEmail ($str) { 
  return (!preg_match( 
   "/[_a-z0-9а-я-]+(\.[_a-z0-9а-я-]+)*@[a-z0-9а-я-]+(\.[a-z0-9а-я-]+)*(\.[a-zа-я]{2,6})$/ui", $str)) 
   ? false : true; 
} 
  
 for ($i=0; $i<count($test); $i++) {
  echo $test[$i].': '.(isEmail($test[$i],FILTER_VALIDATE_EMAIL)?'+':'-').'<br>';
 }
?>

37. Как на PHP сравнить две даты?

Вопрос необъятен и зависит от того, как именно представлены даты. Вот несколько подходов к решению задачи при условии, что даты представляют собой строки формата "ГГГГ-ММ-ДД" или "ГГ-ММ-ДД":

<?php
 $date1 = "20-10-31"; 
 $date2 = "2020-08-21"; 

 echo '$date1 > $date2 :' . ($date1 > $date2 ? 'true' : 'false') . '<br>';
 echo 'strtotime($date1) > strtotime($date2) :' . (strtotime($date1) > strtotime($date2) ? 'true' : 'false') . '<br>';

 $date1Obj = new DateTime($date1); 
 $date2Obj = new DateTime($date2); 
 echo '$date1Obj > $date2Obj :' . ($date1Obj > $date2Obj ? 'true' : 'false') . '<br>';

 echo '$date1 (YYYY-MM-DD)=' . $date1Obj->format("Y-m-d") . '<br>';
 echo '$date2 (YYYY-MM-DD)=' . $date2Obj->format("Y-m-d") . '<br>';
?>

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

$date1 > $date2 :false
strtotime($date1) > strtotime($date2) :true
$date1Obj > $date2Obj :true
$date1 (YYYY-MM-DD)=2020-10-31
$date2 (YYYY-MM-DD)=2020-08-21

38. Есть ли в PHP перечисления (enumerations)?

В чистом виде нет, но легко эмулировать константами класса:

<?php
 abstract class enum { 
  const str = 'String value'; 
  const val = 100; 
  const arr  = [ 'black' => 0, 'white' => 255 ]; 
 } 
 echo enum::str . '<br>';
 echo enum::val . '<br>';
 foreach (enum::arr as $key=>$val) echo  $key . ': ' . $val . '<br>';
?>

39. Чем всё-таки echo отличается от print?

  • echo: принимает список аргументов через запятую, не возвращает значения;
  • print: принимает один аргумент-строку, возвращает значение 1, работает медленнее.

<?php
 $a = 'String';
 $b = 100;
 echo $a, $b, '<br>';
 $r = print $a . $b . '<br>';
 echo "[$r]<br>";
?>

40. Как обрабатывать исключения на PHP?

Примерно так же, как на C++, конструкцией try-throw-catch:

<?php
 function div ($a,$b) {
  $c = INF;
  try {
   if ($b == 0) throw new Exception('Деление на ноль'); 
   $c = $a / $b;
  }
  catch(Exception $e) { 
   echo 'Возникло исключение: ', $e->getMessage(), '<br>'; 
   return INF; //иначе функция будет выполняться дальше
  } 
  //...
  return $c;
 }

 echo div (4,3),'<br>';
 echo div (1,0);
?>

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

<?php
 function div ($a,$b) {
  $c = INF;
  try {
   if ($b == 0) throw new Exception('Деление на ноль'); 
   $c = $a / $b;
  }
  catch(Exception $e) { 
   echo 'Возникло исключение: ', $e->getMessage(), '<br>'; 
   return INF; 
  } 
  finally { 
   echo 'Функция div<br>'; //Выполнится в обоих случаях!
  } 
  //...
  return $c;
 }

 echo div (4,3),'<br>';
 echo div (1,0);
?>
Функция div
1.3333333333333
Возникло исключение: Деление на ноль
Функция div
INF

Наконец, можно написать свой класс для обработки исключений.

<?php
 class myException extends Exception { 
  function __toString() { 
   return 'Ошибка в строке '.$this->getLine().' файла '.$this->getFile().': '.$this->getMessage().'<br>';
  } 
 } 

 function div ($a,$b) {
  $c = INF;
  try {
   if ($b == 0) throw new myException('Деление на ноль'); 
   $c = $a / $b;
  }
  catch(myException $e) { 
   echo 'Возникло исключение: ', $e; 
   return INF; 
  } 
  //...
  return $c;
 }

 echo div (4,3),'<br>';
 echo div (1,0);
?>
1.3333333333333
Возникло исключение: Ошибка в строке 11 файла D:\xampp\htdocs\my\24.php: Деление на ноль
INF

41. Как прервать скрипт с сообщением об ошибке в браузер?

Использовать конструкцию функция or die ('Сообщение') (если функция возвращает false при ошибке) или условный оператор с die.

Если нужно при этом отключить вывод встроенного сообщения, поместите перед именем функции символ "@".

В последнем случае нужно обрабатывать ошибку самим! Примеры:

<?php
 $f = @fopen('data.txt','r') or die ('Не могу открыть файл data.txt');
?>

<?php
 $a = 1; $b = 0;
 if ($b == 0) die ('Деление на ноль!');
 $c = $a / $b;
?>

42. Как динамически изменить имя вызываемой функции?

Самое простое - хранить имя нужной функции в переменной.

<?php
 function inc ($x) { return $x+1; }
 function dec ($x) { return $x-1; }

 $f = 'inc';
 echo $f(1),'<br>'; //2
 $f = 'dec';
 echo $f(1),'<br>'; //0
?>

43. Как проверить, является ли массив ассоциативным (то есть, не "си-подобным", имеет ключи, заданные не по умолчанию)?

<?php 
 $arr1= ["Month1" => "January", "Month2" => "February",  "Month3" => "March"]; //ассоциативный
 $arr2 = [ 1, 2, 3] ; //нет
 $arr3 = [ '1'=>1, '2'=>2, '3'=>3] ; //да, так как ключи не совпадают с умолчаниями
 $arr4 = [ '0'=>1, '1'=>2, '2'=>3] ; //нет, так как ключи совпадают с умолчаниями

 function is_associative ($arr) {
  return array_keys($arr) !== range(0, count($arr) - 1);
 }

 echo var_export(is_associative ($arr1)),'<br>'; //true
 echo var_export(is_associative ($arr2)),'<br>'; //false
 echo var_export(is_associative ($arr3)),'<br>'; //true
 echo var_export(is_associative ($arr4)),'<br>'; //false
?> 

44. Как получить информацию о DNS хоста?

В примере показаны только IPv4 и IPv6-адреса DNS для выбранного хоста.

<?php
 $host = "www.google.com";
 $ipv4_record = dns_get_record ($host,DNS_A);
 $ipv6_record = dns_get_record ($host,DNS_AAAA);
 print "ipv4: " . $ipv4_record[0]["ip"] . "<br>\n";
 print "ipv6: " . $ipv6_record[0]["ipv6"];
?>

45. Как побайтово обработать бинарный файл на PHP?

Подойдут стандартные file_get_contents и file_put_contents, так как они бинарно безопасны, но данные нужно будет преобразовать в массив байт (unpack), а потом изменённые байты упаковать обратно в строку (pack).

В этом примере мы преобразуем русские алфавитные символы кодировки Юникода UTF-8 в их однобайтовые аналоги из кодировки Windows-1251, а другие байты файла не трогаем.

Файл теста 1.txt, также сохранённый в UTF-8, был таким:

АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ
абвгдеёжзийклмнопрстуфхцчшщъыьэюя

И сам листинг (PHP 5.5 и выше):

<?php
 $filename = '1.txt';
 $data = file_get_contents ($filename);
 if ($data === false) {
  echo 'Не могу открыть файл '.$filename;
  exit (1);
 }
 $arr = unpack('C*',$data); //ключи массива будут 1,2,3,...
 $cnt = count($arr);
 $res = [];
 for ($i = 1; $i <= $cnt; $i++) { //пример побайтовой обработки данных из файла
  $byte = $arr[$i];
  if ($byte == 208 or $byte == 209) {
   if ($i < $cnt) $i++;
   else {
    $res[] = $byte;
    break;
   }
   $next = $arr[$i];
   if ($byte == 208) { 
    if ($next > 143 and $next < 192) { $res[] = $next + 48; continue; } //А-Яа-п
    else if ($next == 129) { $res[] = 168; continue; } //Ё
    else $i--;
   }
   else if ($byte == 209) { 
    if ($next > 127 and $next < 144) { $res[] = $next + 112; continue; } //р-я
    else if ($next == 145) { $res[] = 184; continue; } //ё
    else $i--;
   }
  }
  $res[] = $byte;
 }
 $data = pack('C*',...$res); //именно так, иначе весь массив в pack не передать
 $flag = file_put_contents ($filename, $data);
 if ($flag === false) {
  echo 'Ошибка записи в файл '.$filename;
  exit (2);
 }
 echo 'Выполнена обработка файла '.$filename;
?>

46. Как получить и обработать части строки, разделённые какими-либо символами?

Также в примере показано, как регистронезависимо сортировать массив с кириллицей в кодировке Юникода UTF-8.

Возможна и любая другая "ручная" обработка элементов полученного массива слов.

<?php
 $s = "Строка с любыми\nпробельными\tразделителями";
 $parts = preg_split("/\s+/",$s);

 echo '<pre>'; print_r ($parts);  echo '</pre>';
 $parts = array_reverse ($parts);
 echo '<p>В обратном порядке:</p>';
 echo '<pre>'; print_r ($parts);  echo '</pre>';

 $s = "Строка;разделитель - один символ;;точки с запятой";
 $parts = preg_split("/;{1}/",$s);

 echo '<pre>'; print_r ($parts);  echo '</pre>';
 usort ($parts, 
  function ($a, $b) { 
   return strcmp(mb_strtoupper($a, 'UTF-8'), mb_strtoupper($b, 'UTF-8')); 
  }
 );
 echo '<p>После сортировки слов:</p>';
 echo '<pre>'; print_r ($parts);  echo '</pre>';
?>

Результат работы этого примера:

Array
(
    [0] => Строка
    [1] => с
    [2] => любыми
    [3] => пробельными
    [4] => разделителями
)

В обратном порядке:

Array
(
    [0] => разделителями
    [1] => пробельными
    [2] => любыми
    [3] => с
    [4] => Строка
)

Array
(
    [0] => Строка
    [1] => разделитель - один символ
    [2] => 
    [3] => точки с запятой
)

После сортировки слов:

Array
(
    [0] => 
    [1] => разделитель - один символ
    [2] => Строка
    [3] => точки с запятой
)

47. Как вывести и позиционировать на картинке строку шрифтом .ttf?

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

Предполагается, что в одной папке со скриптом находится файл шрифта arial.ttf, скопированный из папки \Windows\fonts

<?php //F5 - обновить картинку в браузере
 function mypic ($n = 200) {
  $size_x = 512; $size_y = 512; //размеры картинки
  $img = imagecreate($size_x,$size_y); //создать рисунок
  $color = imagecolorallocate($img,255,255,255); //создать фоновый цвет - белый
  imagefilledrectangle ($img,0,0,$size_x-1,$size_y-1,$color); //залить им
  //Делаем случайные бары:
  for ($i = 0; $i < $n; $i++) {
   $color = imagecolorallocate($img,rand(103,255),rand(103,255),rand(103,255)); //случайный цвет
   $width = rand (50, 100);
   $height = rand (50, 100);
   $x = rand (1,$size_x - $width - 1);
   $y = rand (1,$size_y - $height - 1);
   imagefilledrectangle ($img,$x,$y,$x+$width-1,$y+$height-1,$color); 
  }
  //Делаем случайную строку:
  $cnt = rand(4, 8); //длина от 4 до 8 символов
  $letter = '';
  for ($i = 0; $i < $cnt; $i++) { //Получаем код 'A', добавляем смещение, преобразуем обратно в символ
   $letter .= chr (ord('A') + rand(0,25)); //Добавляем символ к строке
  }
  $color = imagecolorallocate($img,rand(0,102),rand(0,102),rand(0,102)); //случайный цвет
  $lettersize = 36; //размер шрифта в пунктах
  $font = dirname(__FILE__).'/arial.ttf'; //путь к шрифту в текущей папке
  $box = imagettfbbox ($lettersize,0,$font,$letter);
  //Размеры, возвращаемые imagettfbbox, требуют обработки!
  //Вычисляем ширину и высоту бокса с текстом:
  $min_x = min ( [$box[0], $box[2], $box[4], $box[6]] );
  $max_x = max ( [$box[0], $box[2], $box[4], $box[6]] );
  $min_y = min ( [$box[1], $box[3], $box[5], $box[7]] );
  $max_y = max ( [$box[1], $box[3], $box[5], $box[7]] );
  $width  = $max_x - $min_x;
  $height = $max_y - $min_y; 
  $left   = abs( $min_x ) + $width; //не используется, просто для справки
  $top    = abs( $min_y ) + $height; //не используется, просто для справки
  $x = rand (1, $size_x - $width - 1);
  $y = rand (1 + $height, $size_y - 1); //Y-координата в imagettftext - левый нижний угол!
  imagettftext ($img,$lettersize,0,$x,$y,$color,$font,$letter);
  return $img;
 }

 //Пример вызова функции:
 if (!function_exists('imagecreate')) die ('No GD support!');
 $img = mypic();
 //Отдаём контент для браузера:
 header ('Content-Disposition: inline; filename=image.png'); //У файла будет имя при сохранении
 header ('Content-Type: image/png'); //Отдаем формат .png
 imagepng ($img); //Отдали картинку с сервера
 imagedestroy ($img); //Удалили временный файл
?>

Случайный вывод этого примера:

картинка с барами и строкой
картинка с барами и строкой

48. Как клонировать составной объект, то есть, создать копию всех его свойств и методов?

В PHP есть готовый метод для этого.

<?php
 class T {
  function name() { return "T"; }
 }
 class S {
 function name() { return "S"; }
 }
 $obj1 = new T();
 $obj2 = new S();
 $obj3 = clone $obj1;
 $obj4 = clone $obj2;
 echo $obj3->name(), '<br>', $obj4->name(); // "T" "S"
?>

49. Как получить имя файла с кириллицей и пробелами на локалхосте Windows?

Функция проверена в актуальной сборке Windows 10 на локалхосте XAMPP.

function getFileName ($filename) {
 //Получение имени файла с кириллицей и пробелами - здесь для Windows
 $f = iconv('UTF-8', 'cp1251', $filename);
 $f = str_replace('%28','(',$f);
 $f = str_replace('%29',')',$f);
 $f = str_replace('+','%20',$f);
 return $f;
}

//Далее, например: 
$string = file_get_contents(getFileName("./Мой файл.txt"));

50. Как в callback или вложенной функции использовать переменную, определённую во внешней функции?

<?php
 $foo = '+';
 $bar = function ($bar) use ($foo) { return $foo.$bar; };
  //use работает в этом контексте именно в таком синтаксисе
 echo $bar(14); //+14
?>

Не путать с глобальными переменными, которых в PHP давно нет, хотя есть (супер)глобальные системные массивы, например, $GLOBALS.

51. Как на PHP сгенерировать текстовый файл нужного размера со случайным текстовым содержимым?

Если не нужны очень большие объёмы, то проще всего так:

<?php
function randomFile ($filename, $filesize, $stringsize = 80) {
 //Имя файла, размер в байтах, размер строки в однобайтовых символах
 $characters = 
  '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ        '; //побольше пробелов
 $charactersLength = strlen ($characters);
 if ($h = fopen ($filename, 'w')) {
  while ($filesize > 0) {
   $str = '';
   for ($i = 0; $i < min ($filesize, $stringsize) - 1; $i++) 
    $str .= $characters[rand(0, $charactersLength - 1)];
   fwrite ($h, $str);
   $filesize -= min($filesize, $stringsize);
   if ($filesize >= 0) fwrite ($h, "\n");
  }
  fclose ($h); umask (0000); chmod ($filename, 0644);
  return true;
 }
 return false;
}

randomFile ('test.txt', 4096);
?>

52. Как найти разницу между двумя значениями "дата-время", полученными из формы HTML?

Вот пример, разница даётся в днях, часах и минутах. Следует учесть, что поддержка элемента <input type="datetime-local"> пока что ограничена - по сути, только MS Edge и Chrome + новая Opera.

<?php
 $time1 = $time2 = '';
 if (isset($_POST['time1'])) $time1 = strip_tags(trim($_POST['time1']));
 if (isset($_POST['time2'])) $time2 = strip_tags(trim($_POST['time2']));
 $t1 = new DateTime(str_replace(' ', 'T', $time1));
 $t2 = new DateTime(str_replace(' ', 'T', $time2));
 $interval = $t1->diff($t2);
 echo '<p>'.$interval->format('%a д. %H ч. %I м.').'</p>';
 echo '<form method="post">
 <input type="datetime-local" name="time1" value="'.$time1.'">
 <input type="datetime-local" name="time2"value="'.$time2.'">
 <input type="submit">
</form>';
?>

53. Как округлить число до десятков, полусотен, сотен и т.п. в меньшую или большую сторону?

Бывает нужно, например, если речь идёт о ценниках в интернет-магазине. Первым аргументом функции передаётся число, вторым - "база" округления, если она отрицательная, то округляем вниз, иначе вверх.

<?php
 function fix ($price, $base) {
  return ($base < 0 ? floor ($price/abs($base)) : ceil ($price/$base)) * abs($base);
 }

 $p = 112.50;
 echo fix ($p, -10).'<br>'. //110
  fix ($p, 10).'<br>'.      //120
  fix ($p, -50).'<br>'.     //100
  fix ($p, 50).'<br>'.      //150
  fix ($p, -100).'<br>'.    //100
  fix ($p, 100);            //200
?>

54. Как узнать, где находится активный файл php.ini?

Выполните скрипт из ответа 1 и проверьте в его выдаче путь к файлу в строке Loaded Configuration File. Директивы, не помеченные в первой позиции строки файла символом ";" (точка с запятой), являются активными. После изменения настроек обычно нужно перезапустить локальный хост.

55. Как получить дату и время с удалённого хоста?

Не привлекая достаточно сложных решений, связанных с протоколом NTP, это можно сделать так:

<?php
 $GLOBALS['httpdate'] = null;
 $url = "http://www.google.com/";

 function header_callback($curl, $header) {
  if (preg_match('/^Date:/', $header)) {
   $GLOBALS['httpdate'] = trim(substr($header, 5));
   $GLOBALS['httpdate'] = DateTime::createFromFormat('D, d M Y H:i:s e', $GLOBALS['httpdate']);
  }
  return strlen($header);
 }

 $curl = curl_init($url);
 curl_setopt($curl, CURLOPT_NOBODY, true);
 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
 curl_setopt($curl, CURLOPT_HEADERFUNCTION, 'header_callback');
 curl_exec($curl);
 curl_close($curl);

 echo $GLOBALS['httpdate'] != NULL ? $GLOBALS['httpdate']->format('r') : 'Can\'t get date from URL '.$url;
?>

Предполагается, что целевой сервер возвращает в заголовке HTTP директиву Date и подключено расширение CURL, то есть, строчка в активном файле php.ini (см. ответ 54) выглядит как

extension=curl

56. Как реализовать очередь с приоритетом?

Начиная с версии 5.3 есть готовый класс SplPriorityQueue. Отдельно реализованы классы SplHeap, SplMinHeap и SplMaxHeap.

<?php
 $pq = new SplPriorityQueue;
 $pq->insert('Помыть посуду', 3);
 $pq->insert('Накормить кота', 4);
 $pq->insert('Попить чайку', 5);
 $pq->insert('Поработать', 1);
 $pq->insert('Вернуть долги', 2);
 
 $pq->setExtractFlags(SplPriorityQueue::EXTR_BOTH); //Извлекать и данные, и приоритет
 while (!$pq->isEmpty()) { //Как удобно конвертировать ассоциативный массив в строку
  echo urldecode(http_build_query($pq->extract(),'',', ')).'<br>';
 }
?>
data=Попить чайку, priority=5
data=Накормить кота, priority=4
data=Помыть посуду, priority=3
data=Вернуть долги, priority=2
data=Поработать, priority=1

Обратите внимание, что в современных версиях языка есть и другие стандартные структуры данных.

57. Как выполнять некую функцию, например, с именем main, только тогда, когда скрипт запускается напрямую?

Проще всего, видимо, проверять имя скрипта регулярным выражением.

Файл scriptedmain.php, при прямом выполнении будет вызвана main:

<?php
function func() {
 return 42;
}
 
function main() {
 echo "Main: func() returns " . func() . PHP_EOL;
}
 
if (preg_match("/scriptedmain/", $_SERVER["SCRIPT_NAME"])) {
 main();
}
?>

Вызов функции модуля из другого файла, main не будет вызвана:

<?php
 require_once("scriptedmain.php");
 echo "From other module: func() returns " . func() . PHP_EOL;
?>

21.05.2012, 13:37 [11925 просмотров]


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

показать комментарии (2)