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

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

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

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

Скрипты проверялись на локальном хосте в актуальных на момент добавления того или иного примера версиях PHP 5, а позднее 7 или 8. Для скриптов, работающих со строковыми данными, предполагается использование кодировки Юникода UTF-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)?

В чистом виде нет (UPD - в PHP 8.1 уже таки есть), но легко эмулировать константами класса:

<?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;
?>

58. Для заданного текста в кодировке Юникода UTF-8 определить длину максимальной серии подряд идущих символов, отличных от букв латиницы или кириллицы. Вывести саму цепочку символов, сохраняя возможные "лишние" разделители в ней (пробелы, переводы строки и т.п.)

Так как array_reduce "уменьшает" массив до одного элемента, будет найдена только одна цепочка.

<?php
 header('Content-Type: text/html; charset=utf-8');
 mb_internal_encoding('UTF-8');
 $text = "Текст и сам файл скрипта - в кодировке Юникода UTF-8,
  определяем максимальную длину цепочки любых символов простой (не-расширенной) латиницы
  и кириллицы, отличных от букв...
  ";
 preg_match_all ("/[^a-zA-Zа-яёА-ЯЁ]+/", $text, $matches) or die ("Regexp error!");
 $longStr = array_reduce($matches[0], function ($a, $b) { return mb_strlen($a) > mb_strlen($b) ? $a : $b; });
 echo '<pre>[',$longStr,"]\nДлина=",mb_strlen($longStr),'</pre>';
  //найдено многоточие с 2 пробелами и символами CR/LF из конца $text
?>

59. Как удалить из текста все "лишние" разделители, то есть, любую цепочку из нескольких идущих подряд пробелов, табуляций и/или переводов строки заменить одним разделителем?

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


     \t
 т

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

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

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

  • ^[^\S\r\n]+|[^\S\r\n]+$ заменить на "пусто" (аналог метода trim);
  • затем [^\S\r\n]+ заменить на один пробел.

За одну замену: ^[^\S\r\n]+|[^\S\r\n]+$|[^\S\r\n]+(?=[^\S\r\n]) заменить на "пусто" (оставит между лексемами последний из цепочки разделителей).

60. Как проверить, передано ли значение хотя бы от одного чекбокса на форме и введён ли текстовый комменатарий? Если ничего не выбрано и не введено, вывести соответствующие сообщения (из серии "вечных вопросов").

В простейшем случае, без применения массивов и единых обработчиков параметров POST, можно сделать так (файлы сохранены в кодировке Юникода UTF-8).

Файл типа .html, откуда вызывается zapros.php, расположенный в той же папке:

<!DOCTYPE html>
<html lang="ru">
<head>
 <meta charset="utf-8">
 <title>HTML</title>
</head>
<body>

<h2>Тест</h2>
<form action="zapros.php" method="POST"> 
 <p>
      <input type="checkbox" name="var1" id="var1" value="1"><label for="var1">Вариант 1</label>
  <br><input type="checkbox" name="var2" id="var2" value="2"><label for="var2">Вариант 2</label>
  <br><input type="checkbox" name="var3" id="var3" value="3"><label for="var3">Вариант 3</label>
 </p>
 <p>Ответ:</p>
 <p>
  <textarea name="comments" rows="4" cols="60"></textarea>
 </p>
 <p>    
  <input type="submit" value="Отправить">
  <input type="reset" value="Очистить">
</form>
</body>
</html>

Вызываемый файл zapros.php:

<!DOCTYPE html>
<html lang="ru">
<head>
 <meta charset="utf-8">
 <title>Zapros</title>
</head>
<body>
<?php
 $str = '<p>Вы выбрали вариант(ы): <b>';
 $selected = 0;
 for ($i = 1; $i < 4; $i++) {
  if (isset($_POST['var'.$i])) {
   $str .= $_POST['var'.$i].' ';
   $selected++;
  }
 }
 if (!$selected) $str .= 'ничего не выбрано';
 $str .= '</b></p>';
 $comment = '';
 if (isset($_POST['comments'])) $comment = htmlspecialchars(trim($_POST['comments']),ENT_QUOTES,'UTF-8');
 $str .= "<p>Ваш ответ: <b>".(!empty($comment) ? $comment : 'нет ответа');
 echo $str;
?>
</body>
</html>

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

Листинг не содержит стандартного обрамления HTML, предполагается использование кодировки Юникода UTF-8.

<?php
 mb_internal_encoding("UTF-8");
 $filename = 'content.txt';
 $val = '';
 if (file_exists($filename) and is_file($filename)) {
  $val = file_get_contents ($filename);
  if ($val === false) die ('Ошибка чтения файла '.$filename);
 }
 if (isset($_POST['submit'])) {
  if (isset($_POST['val'])) $val = trim(htmlspecialchars($_POST['val']));
  file_put_contents ($filename, $val) or die ('Ошибка записи в файл '.$filename);
 }
?>
<form method="post">
<p><textarea rows="10" cols="80" maxlength="2048" name="val"><?php echo $val; ?></textarea></p>
<p><input type="submit" name="submit"></p>
</form>

62. Создать программно $cnt скриптов в текущей папке и список ссылок на них. Каждый скрипт может учитывать количество своих посещений. Информация о посещениях хранится в текстовом файле.

Этот код довольно мозгодробителен и был предназначен для иллюстративных целей :)

<!DOCTYPE html>
<html lang="ru">
 <head>
  <meta charset="UTF-8">
  <title>Список файлов</title>
 </head>
 <body>
<?php
 $cnt = 10;
 $filename = 'cnt.txt';
 $c = array_fill (0, $cnt, 0);
 if (file_exists($filename) and is_file($filename)) {
  $c = file($filename);
 }
 else {
  file_put_contents ($filename, implode("\n", $c)) or die ('Ошибка записи в файл '.$filename);
 }
 for ($i = 0; $i < $cnt; $i++) {
  $filename = $i.'.php';
  if (!file_exists($filename) or !is_file($filename)) {
   $code = '<?php
 $filename = \'cnt.txt\'; $n = 0; 
 if (isset($_GET[\'n\']) and intval($_GET[\'n\']) > -1) $n = intval(trim($_GET[\'n\'])); 
 $c = file($filename) or die (\'Ошибка чтения файла \'.$filename);
 array_walk($c, function(&$val, $key) { $val = intval(trim($val)); });
 $c[$n]++;
 file_put_contents ($filename, implode("\n", $c)) or die (\'Ошибка записи в файл \'.$filename); 
 echo $c[$n];
?>';
   $template = '<!DOCTYPE html>
<html lang="ru">
 <head>
  <meta charset="UTF-8">
  <title>'.$filename.'</title>
 </head>
 <body>
  <h1>'.$filename.'</h1>
  <p>Count: '.$code.'</p>
 </body>
</html>';
   file_put_contents ($filename, $template) or die ('Ошибка записи в файл '.$filename);
  }
 }
 for ($i = 0; $i < $cnt; $i++) {
  echo '<p><a href="'.$i.'.php?n='.$i.'">'.$i.'.php</a></p>';
 }
?>
 </body>
</html>

63. Задача о садовниках. Известны сорта роз, выращиваемых тремя цветоводами: "Анжелика", "Виктория", "Гагарин", "Ave Maria", "Катарина", "Юбилейная". Определить те сорта, которые имеются у каждого из цветоводов, есть хотя бы у одного из цветоводов, а также сорта, которых нет ни у одного из цветоводов.

В основном, для иллюстрации манипуляций с массивами и ради функции rnd ($cnt, $size) - выбор $cnt различных между собой случайных чисел из диапазона значений [0;$size-1].

<?php
 mb_internal_encoding("UTF-8");
 $sorts = ["Анжелика" => 0, "Виктория"  => 0, "Гагарин"  => 0, "Ave Maria" => 0, "Катарина"  => 0, "Юбилейная" => 0];
 $gardeners = [];

 $keys = array_keys ($sorts);
 echo 'Сорта:<pre>'.print_r($keys,true).'</pre>'; //Выводим список сортов
 for ($i = 0; $i < 3; $i++) { //Даём каждому садовнику по 3-4 разных сорта
  $gardeners[$i] = array_intersect_key($keys,array_flip(rnd(array_rand(array_flip([3,4])),count($sorts))));
 }
 echo 'Садовники:<pre>'.print_r($gardeners,true).'</pre>'; //Выводим распределение сортов по садовникам
 foreach ($sorts as $key => $val) { //Считаем по сортам,
  for ($i = 0; $i < 3; $i++) { //кому из садовников они достались
   $cnt = array_search ($key,$gardeners[$i]);
   if ($cnt !== false) $sorts[$key]++;
  }
 }
 foreach ($sorts as $key => $val) { //Делаем выводы
  echo $key.': '.($val ==  count($gardeners) ? 'у каждого' : ($val == 0 ? 'ни у кого' : 'хотя бы у одного')).'<br>';
 }
 function rnd ($cnt, $size) { //$cnt различных случайных чисел из диапазона [0;$size-1]
  if ($cnt < 1 or $size < 1) return [];
  if ($cnt > $size) $cnt = $size;
  $arr = range(0, $size-1);
  shuffle ($arr);
  return array_slice ($arr, 0, $cnt);
 }
?>

Пример вывода скрипта:

Сорта:

Array
(
    [0] => Анжелика
    [1] => Виктория
    [2] => Гагарин
    [3] => Ave Maria
    [4] => Катарина
    [5] => Юбилейная
)

Садовники:

Array
(
    [0] => Array
        (
            [1] => Виктория
            [2] => Гагарин
            [3] => Ave Maria
            [4] => Катарина
        )

    [1] => Array
        (
            [0] => Анжелика
            [1] => Виктория
            [3] => Ave Maria
            [4] => Катарина
        )

    [2] => Array
        (
            [0] => Анжелика
            [3] => Ave Maria
            [4] => Катарина
        )

)

Анжелика: хотя бы у одного
Виктория: хотя бы у одного
Гагарин: хотя бы у одного
Ave Maria: у каждого
Катарина: у каждого
Юбилейная: ни у кого

64. Как отобразить текущую дату прописью?

Функция strftime (см. ответ 25) начиная с версии PHP 8.1 объявлена устаревшей.

Ниже в одном листинге (с комментариями и примером вывода) показано три подхода к решению задачи без этой функции.

Чтобы вариант 2 cработал и не вылезло сообщение Fatal error: Uncaught Error: Class "IntlDateFormatter" not found, в активном файле php.ini (обычно это \xampp\php\php.ini) включите соответствующее расширение (уберите точку с запятой в первой позиции строки)

;extension=intl

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

;extension=php_intl.dll

<?php
 //Вариант 1 - самый простой, но он не поддерживает локали!
 echo date('d F Y, l, H:i:s P'); //Форматирование и вывод
  //03 April 2022, Sunday, 15:00:39 +02:00

 //Вариант 2, с классами DateTimeZone и IntlDateFormatter. Увы, скажет не "апреля", а "апрель"
 $timezone_string = date_default_timezone_get(); //Временная зона строкой
 $timezone = new DateTimeZone($timezone_string);
 $date = new DateTime(null, $timezone); //Объект с текущей датой и временем
 $formatter = new IntlDateFormatter ('ru_RU', //Объект, выполняющий форматирование
  IntlDateFormatter::FULL, IntlDateFormatter::FULL, $timezone);
 $formatter->setPattern('d LLLL Y, eeee, HH:mm:ss OOOO'); //Форматирование
 echo '<br>'.$formatter->format($date); //Вывод
  //3 апрель 2022, воскресенье, 15:00:39 GMT+02:00
  //Форматы есть на https://unicode-org.github.io/icu/userguide/format_parse/datetime/

 //Вариант 3, сами форматируем данные, полученные из DateTime
 $date = new DateTime(null, new DateTimeZone(date_default_timezone_get()));
 $date_string = $date->format('H/i/s/j/m/Y/w/P');
 list ($h, $m, $s, $d, $mon, $y, $w, $z) = explode("/", $date_string);
 $months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 
  'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'];
 $days = ['воскресенье','понедельник', 'вторник', 'среда', 'четверг','пятница','суббота'];
 $date_string = sprintf ("%d %s %d, %s, %02d:%02d:%02d GMT%s", 
  $d, $months[$mon-1], $y, $days[$w], $h, $m, $s, $z);
 echo '<br>'.$date_string;
  //3 апреля 2022, воскресенье, 15:00:39 GMT+02:00
?>

65. Как в тексте целиком выделить слова, содержащие строки из заданного списка тегов?

Вот листинг и вывод примера.

<?php
 $text = 'Квазимордовороты названы так потому, что некоторые из них образуют даже собственные квазикультуры, 
такие как хорошо изученные притворец отвратный, задолбыш садюжный выпрямляющийся, подлоносец получервячный, 
бабояжница плесневидная самодовольная, зловонец пупырчато-перепончатый редкостный и полугениталец лысый 
веснушчатый. Обратите внимание, что рассматриваемый вид отличается от последнего в списке лишь невероятной 
тягой к плотоядности, притом что различия между так называемым "человеком" и его ближайшими поедаемыми 
им сородичами абсолютно ничтожны. Более того, мы можем постулировать, что "человек" на протяжении большей 
части своей так называемой "эволюции" (а на самом деле типичного "прозябания безысходного, 
садистически-рвотно-перемежающегося") употреблял в пищу и представителей своего вида, 
как бы невероятно и чудовищно это не прозвучало для вас.'; //Наш текст
 $tags = ['Квази', 'человек', 'про', 'ости', '\.']; //Наши теги, слова с которыми выделятся
  //Точку и другие метасимволы, критичные для PCRE, если они есть в тегах,  надо экранировать!
  //См. список на https://www.php.net/manual/ru/regexp.reference.meta.php

 $patterns = array_map(function($word) { return "#\w*$word\w*#iu"; },  $tags); 
 $result = preg_replace_callback ($patterns, function($matches) { return "<b>{$matches[0]}</b>"; }, $text);
 
 echo $result;
?>
Вывод примера
Вывод примера

Если слово целиком выделять не нужно, а только конкретно часть, составляющую тег, меняем в $patterns строку шаблона на "#$word#iu"

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

What is the smallest positive integer whose square ends in the digits 269,696? Babbage, letter to Lord Bowden, 1837; in: Hollingdale and Tootill, Electronic Computers, second edition, 1970, p. 12

<?php
 $digits = 269696;
 $depth = pow(10,strlen((string)$digits));
 $i = 1;
 for (; ($i * $i) % $depth != $digits; $i++);
 echo $i, ' * ', $i, ' = ', ($i * $i), PHP_EOL;
?>

67. Имея документ XML и определение схемы XSD, проверить, соответствует ли документ описанной схеме.

Тестовые документы shiporder.xml и shiporder.xsd в кодировке Юникода UTF-8 (сохранены в текущей папке скрипта) взяты отсюда.

<?php
 libxml_use_internal_errors(true);
 
 $xml = new DOMDocument();
 $xml->load('./shiporder.xml');
 
if (!$xml->schemaValidate('./shiporder.xsd')) {
 var_dump(libxml_get_errors()); exit;
} 
else {
 echo 'Success, no errors';
}
?>
Файл shiporder.xml
<?xml version="1.0" encoding="UTF-8"?>

<shiporder orderid="889923"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="shiporder.xsd">
  <orderperson>John Smith</orderperson>
  <shipto>
    <name>Ola Nordmann</name>
    <address>Langgt 23</address>
    <city>4000 Stavanger</city>
    <country>Norway</country>
  </shipto>
  <item>
    <title>Empire Burlesque</title>
    <note>Special Edition</note>
    <quantity>1</quantity>
    <price>10.90</price>
  </item>
  <item>
    <title>Hide your heart</title>
    <quantity>1</quantity>
    <price>9.90</price>
  </item>
</shiporder> 
Файл shiporder.xsd
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="shiporder">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="orderperson" type="xs:string"/>
      <xs:element name="shipto">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="address" type="xs:string"/>
            <xs:element name="city" type="xs:string"/>
            <xs:element name="country" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="item" maxOccurs="unbounded">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="title" type="xs:string"/>
            <xs:element name="note" type="xs:string" minOccurs="0"/>
            <xs:element name="quantity" type="xs:positiveInteger"/>
            <xs:element name="price" type="xs:decimal"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
    <xs:attribute name="orderid" type="xs:string" use="required"/>
  </xs:complexType>
</xs:element>

</xs:schema> 

68. Из данных в формате XML извлечь значения заданных атрибутов заданного элемента.

<?php
 $data = '<Люди>
  <Человек Имя="Анархия" Пол="Ж" ДатаРождения="1999-01-02" />
  <Человек Имя="Стакан портвейна" Пол="М" ДатаРождения="2000-03-04" />
  <Человек Имя="Паровоз по делу" Пол="М" ДатаРождения="2001-05-06" />
  <Человек Имя="Чудинище" Пол="М"  ДатаРождения="2002-07-08">
    <Питомец Тип="Собака" Имя="Бобик" />
  </Человек>
  <Человек ДатаРождения="2003-09-10" Пол="Ж" Имя="Мать порядка" />
</Люди>';
 $xml = new XMLReader();
 $xml->xml($data);
 while ($xml->read())
  if (XMLREADER::ELEMENT == $xml->nodeType && $xml->localName == 'Человек')
   echo $xml->getAttribute('Имя').'<br>';
?>

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

Анархия
Стакан портвейна
Паровоз по делу
Чудинище
Мать порядка

69. Создать простой DOM и сериализовать его.

<?php
 $dom = new DOMDocument();
 $dom->formatOutput = true;
 $root = $dom->createElement('root');
 $element = $dom->createElement('element');
 $element->appendChild($dom->createTextNode('Текстовый элемент'));
 $root->appendChild($element);
 $dom->appendChild($root);
 $xmlstring = $dom->saveXML();
 echo '<textarea>'.$xmlstring.'</textarea>';
?>

Вывод, полученный в текстовом поле <textarea>:

<?xml version="1.0"?>
<root>
  <element>Текстовый элемент</element>
</root>

70. Имея заданный документ XML, выполнить следующие 3 типовых действия над ним:

  1. получить первый элемент "item";
  2. выполнить действие над каждым элементом "price" (распечатать его);
  3. получить массив всех элементов "name".

<?php
 $doc = new DOMDocument();
 $doc->load('./inventory.xml');
 //или $doc->loadXML('<inventory title="">...</inventory>');
 $xpath = new DOMXPath($doc);

 //Задача 1:
 $nodelist = $xpath->query('//item');
 $result = $nodelist->item(0); 
 var_dump ($result);

 //Задача 2:
 $nodelist = $xpath->query('//price');
 for($i = 0; $i < $nodelist->length; $i++) {
  echo '<br>'.$doc->saveXML($nodelist->item($i));
 }

 //Задача 3:
 $nodelist = $xpath->query('//name');
 $result = []; 
 foreach($nodelist as $node) {
  $result[] = $node; 
  echo '<br>'.$node->textContent;
 }
 echo '<br>';
 var_dump($result);
?>

Файл inventory.xml располагается в той же папке, что и скрипт, предполагается, что он сохранён в кодировке Юникода UTF-8:

<inventory title="Our Store Stuff">
 <section name="health">
  <item id="1">
   <name>Шапка-невидимка</name>
   <price>1144.50</price>
   <description>Делает Вас невидимым</description>
  </item>
  <item id="2">
   <name>Левитационный крем</name>
   <price>230.99</price>
   <description>Левитируйте до трёх часов после употребления</description>
  </item>
 </section>
 <section name="food">
  <item id="3">
   <name>Тухляк в таблетках</name>
    <price>14.99</price>
    <description>Вкусная еда в таблетках; просто добавьте водки</description>
  </item>
  <item id="4">
   <name>Крылышки гробовые</name>
   <price>13.00</price>
   <description>Сделают Ваш гроб летающим; просто добавьте водки</description>
  </item>
 </section>
</inventory>

71. Реализовать мини-сервис для работы с последовательностью натуральных чисел от 1 до N, например: список содержит следующие операции: четные, нечетные, простые, составные. Вывести все числа из диапазона от 1 до N, согласно выбранному из списка действию. Значение N вводится пользователем в текстовое поле.

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

<!DOCTYPE html>
<html lang="ru">
 <head>
  <meta charset="UTF-8">
  <title>Numbers</title>
 </head>
 <body>

<?php
 $n = 10;
 if (isset($_POST['n']) and is_numeric($n)) $n = abs(intval($_POST['n']));
 if ($n == 0) $n = 1; //нуля нет по условиям
 if ($n > 9999) $n = 9999; //избегаем чисел вроде 1e99
 $task = 1;
 if (isset($_POST['task']) and is_numeric($task)) $task = abs(intval($_POST['task'])); 
 if ($task < 1 or $task > 4) $task = 1;
?>

 <form method="post">
  <p>Вывести: 
   <select size="1" name="task">
<?php
 $options = ['четные','нечетные','простые','составные'];
 for ($i = 1; $i < 5; $i++)
  echo '<option value="'.$i.'"'.($task==$i ?' selected':'').'>'.$options[$i-1].'</option>';
?>
   </select>
  </p><p>N=
   <input type="text" name="n" size="5" maxlength="4" value="<?php echo $n; ?>">
  </p><p>
   <input type="submit" name="action" value="Выполнить">
  </p>
 </form>

<?php
 function isPrime ($num) { //Проверка $num на простоту
  if ($num != floor($num) || $num < 2) return false; 
   //вещественные или отрицательные или 1 - не простые числа
  if ($num < 4) return true; //2 и 3 - да
  if ($num % 2 == 0) return false; //чётные - нет
  $ceil = ceil(sqrt($num));
  for ($i = 3; $i <= $ceil; $i += 2) { //остальные проверяем
   if ($num % $i == 0) return false;
  }
  return true;
 }

 if (isset($_POST['action'])) {
  $arr = range (1, $n);
  $result = [];
  switch ($task) {
   case 1:
    $result = array_filter ($arr, function ($item) { return $item%2==0; });
   break;
   case 2:
    $result = array_filter ($arr, function ($item) { return $item%2!=0; });
   break;
   case 3:
    $result = array_filter ($arr, function ($item) { return isPrime($item); });
   break;
   case 4:
    $result = array_filter ($arr, function ($item) { return !isPrime($item) and $item != 1; });
                                                                   //1 также не составное число
   break;
  }
  if (count($result) > 0) echo '<p>'.implode(', ',$result).'</p>';
 }
?>
</body></html>

72. Подсчитать информационную энтропию по Шеннону для заданной текстовой строки.

<?php
 function shannonEntropy($string) {
  $h = 0.0;
  $len = mb_strlen ($string,'UTF-8');
  foreach (count_chars($string, 1) as $count) {
   $h -= (double) ($count / $len) * log((double) ($count / $len), 2);
  }
  return $h;
 }

 $strings = array(
  '00001111',
  'Hello, world!',
  'Привет, мир!'
 );

 foreach ($strings AS $string) {
  printf ('%s : %s<br>' . PHP_EOL, $string, number_format(shannonEntropy($string), 3));
 }
?>

73. Написать скрипт, который вычисляет и показывает информационную энтропию по Шеннону (см. решение 72) для собственного исходного текста.

<?php
 $h = 0;
 $s = file_get_contents(__FILE__);
 $l = strlen($s);
 foreach (count_chars($s, 1) as $c)
  $h -= ($c/$l)*log($c/$l,2);
 echo $h;
?>

74. Подсчитать основные величины, используемые для усреднения - арифметическое среднее, круговое (угловое) среднее, среднее время, медиана, мода, пифагорейские средние, среднее квадратическое.

Все расчёты выполнены в одном скрипте, ссылки на определения из "Вики" есть непосредственно в листинге.

<?php
 //1. Арифметическое среднее
 $arr = [ 1, 2, 2, 3, 4, 7, 9 ]; //числа
 $avg = array_sum($arr) / count($arr);
 printf ('Arithmetic mean = %s<br>' . PHP_EOL, number_format($avg,3));

 //2. Круговое или угловое среднее https://en.wikipedia.org/wiki/Circular_mean
 function meanAngle ($angles) {
  $y_part = $x_part = 0;
  $size = count($angles);
  for ($i = 0; $i < $size; $i++){
   $x_part += cos(deg2rad($angles[$i]));
   $y_part += sin(deg2rad($angles[$i]));
  }
  $x_part /= $size;
  $y_part /= $size;
  return rad2deg(atan2($y_part, $x_part));
 }
 $angles = [90, 180, 270, 360]; //углы
 $mavg = meanAngle($angles);
 printf ('Mean angle = %s deg.<br>' . PHP_EOL, number_format($mavg,3));

 //3. Среднее время ЧЧ:ММ:СС
 function time2ang($tim) {
  if (!is_string($tim)) return $tim;
  $parts = explode(':',$tim);
  if (count($parts)!=3) return $tim;
  $sec = ($parts[0]*3600)+($parts[1]*60)+$parts[2];
  $ang = 360.0 * ($sec/86400.0);
  return $ang;
 }
 function ang2time($ang) {
  if (!is_numeric($ang)) return $ang;
  $sec = 86400.0 * $ang / 360.0;
  $parts = array(floor($sec/3600),floor(($sec % 3600)/60),$sec % 60);
  $tim = sprintf('%02d:%02d:%02d',$parts[0],$parts[1],$parts[2]);
  return $tim;
 }
 function meanang($ang) {
  if (!is_array($ang)) return $ang;
  $sins = 0.0;
  $coss = 0.0;
  foreach($ang as $a) {
   $sins += sin(deg2rad($a));
   $coss += cos(deg2rad($a));
  }
  $avgsin = $sins / (0.0+count($ang));
  $avgcos = $coss / (0.0+count($ang));
  $avgang = rad2deg(atan2($avgsin,$avgcos));
  while ($avgang < 0.0) $avgang += 360.0;
  return $avgang;
 }
 $times = array('15:00:00','18:30:30','00:00:00','23:59:59');
 $angs = [];
 foreach ($times as $t) $angs[] = time2ang($t);
 $ma = meanang($angs);
 $result = ang2time($ma);
 printf ('The mean time of day = %s (angle %s)<br>'. PHP_EOL,$result,number_format($ma,3));

 //4. Медиана https://en.wikipedia.org/wiki/Median
 function median($arr) {
  sort($arr);
  $count = count($arr);
  $middleval = floor(($count-1)/2);
  if ($count % 2) $median = $arr[$middleval];
  else {
   $low = $arr[$middleval];
   $high = $arr[$middleval+1];
   $median = (($low+$high)/2);
  }
  return $median;
 }
 printf ('Median = %s<br>' . PHP_EOL, number_format(median($arr),3)); //тест из расчёта 1

 //5. Мода https://en.wikipedia.org/wiki/Mode_(statistics)
 function mode($arr) {
  if (count($arr)<1) return null;
  $count = array_count_values($arr);
  $best = max($count);
  $keys = array_keys($count, $best);
  return $keys[0];
 }
 printf ('Mode = %s<br>' . PHP_EOL, number_format(mode($arr),3)); //тест из расчёта 1

 //6. Пифагорейские средние https://en.wikipedia.org/wiki/Pythagorean_means
 function ArithmeticMean(array $values) {
  return array_sum($values) / count($values);
 }
 function GeometricMean(array $values) {
  return array_product($values) ** (1 / count($values));
 }
 function HarmonicMean(array $values) {
  $sum = 0;
  foreach ($values as $value) $sum += 1 / $value;
  return count($values) / $sum;
 }
 printf ('Arithmetic mean = %s<br>' . PHP_EOL, number_format(ArithmeticMean($arr),3)); //тест из расчёта 1
 printf ('Geometric mean = %s<br>' . PHP_EOL, number_format(GeometricMean($arr),3));
 printf ('Harmonic mean = %s<br>' . PHP_EOL, number_format(HarmonicMean($arr),3));

 //7. Среднее квадратическое https://en.wikipedia.org/wiki/Root_mean_square
 function RootMeanSquare (array $values) {
  $sum = 0;
  foreach ($values as $number) $sum += pow($number,2);
  return sqrt($sum / count($values));
 }
 printf ('Root mean square = %s<br>' . PHP_EOL, number_format(RootMeanSquare($arr),3)); //тест из расчёта 1
?>

75. Напечатать символы Юникода в кодировке UTF-8 из заданного диапазона.

Просто используйте mb_chr вместо однобайтовой chr.

<?php
 for ($c = 1040; $c < 1104; $c++) echo mb_chr($c,'UTF-8'),' ';
?>

76. Удалить из строки в кодировке Юникода UTF-8 все символы набора, заданного строкой.

<?php
 mb_internal_encoding('UTF-8');
 mb_regex_encoding('UTF-8');

 function stripchars ($s, $chars) {
  return mb_eregi_replace('['.$chars.']','',$s);
   //не пытайтесь делать это через str_replace для кодировки UTF-8
 }

 $s = 'В этом примере мы удалим из строки кириллицы пару гласных.';
 echo $s.'<br>'.stripchars($s, 'ае');
?>

77. Взаимная рекурсия на PHP.

Две функции называются взаимно рекурсивными, если первая вызывает вторую, а вторая, в свою очередь, вызывает первую. Хорошим примером могут служить мужская и женская последовательности Хофштадтера.

<?php
function F($n) {
 if ( $n == 0 ) return 1;
 return $n - M(F($n-1));
}

function M($n) {
 if ( $n == 0) return 0;
 return $n - F(M($n-1));
}

 $ra = [];
 $rb = [];
 $cnt = 100; //количество членов последовательностей
 for($i=0; $i < $cnt; $i++) {
  $ra[] = F($i);
  $rb[] = M($i);
 }
 echo implode(' ', $ra) . "<br>\n";
 echo implode(' ', $rb);
?>

78. Как разбить текст на предложения, которые заканчиваются одним из знаков ".", "?", "!"?

Cм. также примеры 21, 59.

<?php
 $text = 'Шалтай-Болтай сидел на стене.   Шалтай-Болтай 

  
 свалился во сне! Как  собрать?! Не знаем, 	 но собираем    ,.?!   		

Соберём
или
нет - 
дай ответ     	  ';

 $html = [];
 $text = str_replace(array("\r", "\n"), ' ', $text); //Разбить по переводам строк
 $text = trim(preg_replace('/[ \t]+/', ' ', $text)); //Убрать лишние разделители
 if (mb_strpos(".?!",mb_substr($text, -1, 1, 'UTF-8'),0,'UTF-8')===false)
  $text .= '.'; //Если надо, добавить точку в конце
 preg_match_all("/.*?[.?!](?:\s|$)/s", $text, $items); //Разбить по концам предложений
 if (!empty($items[0])) {
  foreach ($items[0] as $item) { //Получить массив предложений
   $html[] = '<p>'.trim($item).'</p>';
  }
 } 
 else {
  $html[] = '<p>'.$text.'</p>';
 }

 echo implode(PHP_EOL, $html);
?>
<p>Шалтай-Болтай сидел на стене.</p>
<p>Шалтай-Болтай свалился во сне!</p>
<p>Как собрать?!</p>
<p>Не знаем, но собираем ,.?!</p>
<p>Соберём или нет - дай ответ.</p>

79. Как "собрать" обратно URL-адрес, разбитый на части функцией parse_url?

Готовой "обратной" функции нет, но её можно написать. Вот листинг и тест:

<?php
 function reverse_parse_url(array $parts) {
  $url = '';
  if (!empty($parts['scheme'])) $url .= $parts['scheme'] . ':';
  if (!empty($parts['user']) || !empty($parts['host'])) $url .= '//';
  if (!empty($parts['user'])) $url .= $parts['user'];
  if (!empty($parts['pass'])) $url .= ':' . $parts['pass'];
  if (!empty($parts['user'])) $url .= '@';
  if (!empty($parts['host'])) $url .= $parts['host'];
  if (!empty($parts['port'])) $url .= ':' . $parts['port'];
  if (!empty($parts['path'])) $url .= $parts['path'];
  if (!empty($parts['query'])) {
   if (is_array($parts['query'])) $url .= '?' . http_build_query($parts['query']);
   else $url .= '?' . $parts['query'];
  }
  if (!empty($parts['fragment'])) $url .= '#' . $parts['fragment'];
  return $url;
 }
 
 $url = "https://neolurk.org/wiki/Если_не_Путин,_то_кто%3F";
 $arr = parse_url($url);
 print_r ($arr);
 $url = reverse_parse_url ($arr);
 print_r ($url);
?>

80. Как бороться с частично кириллическими URL?

Примеры таких адресов приведены ниже в листинге. Неведомыми путями они часто попадают на автообработку.

Заметим, что стандартная функция filter_var не работает с кириллицей в ссылках, а согласно RFC, кириллицы там и быть не должно.

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

<?php
 function my_url_encode($s) {
  $s= strtr ($s, array (
   " "=> "%20", "а"=>"%D0%B0", "А"=>"%D0%90","б"=>"%D0%B1", "Б"=>"%D0%91", "в"=>"%D0%B2", "В"=>"%D0%92", 
   "г"=>"%D0%B3", "Г"=>"%D0%93", "д"=>"%D0%B4", "Д"=>"%D0%94", "е"=>"%D0%B5", "Е"=>"%D0%95", 
   "ё"=>"%D1%91", "Ё"=>"%D0%81", "ж"=>"%D0%B6", "Ж"=>"%D0%96", "з"=>"%D0%B7", "З"=>"%D0%97", 
   "и"=>"%D0%B8", "И"=>"%D0%98", "й"=>"%D0%B9", "Й"=>"%D0%99", "к"=>"%D0%BA", "К"=>"%D0%9A", 
   "л"=>"%D0%BB", "Л"=>"%D0%9B", "м"=>"%D0%BC", "М"=>"%D0%9C", "н"=>"%D0%BD", "Н"=>"%D0%9D", 
   "о"=>"%D0%BE", "О"=>"%D0%9E", "п"=>"%D0%BF", "П"=>"%D0%9F", "р"=>"%D1%80", "Р"=>"%D0%A0", 
   "с"=>"%D1%81", "С"=>"%D0%A1", "т"=>"%D1%82", "Т"=>"%D0%A2", "у"=>"%D1%83", "У"=>"%D0%A3", 
   "ф"=>"%D1%84", "Ф"=>"%D0%A4", "х"=>"%D1%85", "Х"=>"%D0%A5", "ц"=>"%D1%86", "Ц"=>"%D0%A6", 
   "ч"=>"%D1%87", "Ч"=>"%D0%A7", "ш"=>"%D1%88", "Ш"=>"%D0%A8", "щ"=>"%D1%89", "Щ"=>"%D0%A9", 
   "ъ"=>"%D1%8A", "Ъ"=>"%D0%AA", "ы"=>"%D1%8B", "Ы"=>"%D0%AB", "ь"=>"%D1%8C", "Ь"=>"%D0%AC", 
   "э"=>"%D1%8D", "Э"=>"%D0%AD", "ю"=>"%D1%8E", "Ю"=>"%D0%AE", "я"=>"%D1%8F", "Я"=>"%D0%AF"));
  return $s;
 }
 function myurlencode ($url) { //true или false
  if (filter_var($url, FILTER_VALIDATE_URL)) return true;
  if (filter_var(my_url_encode($url), FILTER_VALIDATE_URL)) return true;
  return false;
 }
 
 $urls = [
  "https://neolurk.org/wiki/Если_не_Путин,_то_кто%3F",
  "https://yandex.ru/search/?text=тестик&lr=65",
  "https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%81%D1%82",
  "http://абракадабра.рф",
  "http://abracadabra.ru?q=Запросик сайту"
 ];
 foreach ($urls as $url) {
  $result = (myurlencode($url) !== false ? "Да" : "Нет");
  echo $url.': '.$result.'<br>';
 }
?>

Другие подходы показались мне заметно сложнее.

Нужно учесть, что домен в URL-адресе, отдаваемом функции filter_var должен быть стандартным, то есть, состоящим из латиницы, а также ссылка должна быть полной, то есть, начинаться с протокола http://, https:// и т.п.

Можно написать функцию и для обратного преобразования "закодированного" URL в исходный:

function my_url_decode($s){
  $s= strtr ($s, array (
   "%20"=>" ", "%D0%B0"=>"а", "%D0%90"=>"А", "%D0%B1"=>"б", "%D0%91"=>"Б", "%D0%B2"=>"в", "%D0%92"=>"В", 
   "%D0%B3"=>"г", "%D0%93"=>"Г", "%D0%B4"=>"д", "%D0%94"=>"Д", "%D0%B5"=>"е", "%D0%95"=>"Е", 
   "%D1%91"=>"ё", "%D0%81"=>"Ё", "%D0%B6"=>"ж", "%D0%96"=>"Ж", "%D0%B7"=>"з", "%D0%97"=>"З", 
   "%D0%B8"=>"и", "%D0%98"=>"И", "%D0%B9"=>"й", "%D0%99"=>"Й", "%D0%BA"=>"к", "%D0%9A"=>"К", 
   "%D0%BB"=>"л", "%D0%9B"=>"Л", "%D0%BC"=>"м", "%D0%9C"=>"М", "%D0%BD"=>"н", "%D0%9D"=>"Н", 
   "%D0%BE"=>"о", "%D0%9E"=>"О", "%D0%BF"=>"п", "%D0%9F"=>"П", "%D1%80"=>"р", "%D0%A0"=>"Р", 
   "%D1%81"=>"с", "%D0%A1"=>"С", "%D1%82"=>"т", "%D0%A2"=>"Т", "%D1%83"=>"у", "%D0%A3"=>"У", 
   "%D1%84"=>"ф", "%D0%A4"=>"Ф", "%D1%85"=>"х", "%D0%A5"=>"Х", "%D1%86"=>"ц", "%D0%A6"=>"Ц", 
   "%D1%87"=>"ч", "%D0%A7"=>"Ч", "%D1%88"=>"ш", "%D0%A8"=>"Ш", "%D1%89"=>"щ", "%D0%A9"=>"Щ", 
   "%D1%8A"=>"ъ", "%D0%AA"=>"Ъ", "%D1%8B"=>"ы", "%D0%AB"=>"Ы", "%D1%8C"=>"ь", "%D0%AC"=>"Ь", 
   "%D1%8D"=>"э", "%D0%AD"=>"Э", "%D1%8E"=>"ю", "%D0%AE"=>"Ю", "%D1%8F"=>"я", "%D0%AF"=>"Я"));
  return $s;
 }
 //...
 $url = "https://neolurk.org/wiki/Если_не_Путин,_то_кто%3F";
 echo my_url_decode(my_url_encode($url));

Предполагается, что обе функции работают с кодировкой UTF-8 Юникода.

81. Как выполнить серию замен строк в текстовом файле, например, при замене строк шаблона на их значения?

Предполагаем, что строки шаблона имеют вид %строка%, их список в виде ассоциативного массива находится в $vars, а тестовый файл с именем page.html располагается в той же папке, что и текущий скрипт.

Тогда для следующего содержимого файла page.html

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title>%title%</title>
  <style>
   body {
    color: %color%;
    background-color: %backcolor%;
   }
  </style>
</head>
<body>
 <p>Содержимое документа</p>
</body>
</html>

показанным ниже скриптом

<?php
 function html ($path, $vars){
  if (file_exists($path) and is_file($path)) {
   $file = file_get_contents ($path);
   return strtr ($file,$vars);
  }
  return 'Bad file name: '.$path;
 }
 
 $vars = ['%color%'=>'#000', '%backcolor%'=>'#fff', '%title%'=>'Моя страница'];
  //список замен
 echo '<pre>'.htmlspecialchars(html ('./page.html',$vars),ENT_COMPAT,'UTF-8').'</pre>';
  //печатаем разметку документа вместо вывода HTML
?>

мы выведем в браузер

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title>Моя страница</title>
  <style>
   body {
    color: #000;
    background-color: #fff;
   }
  </style>
</head>
<body>
 <p>Содержимое документа</p>
</body>
</html>

Для печати документа "как есть", разумеется, подойдёт просто

echo html('./page.html',$vars);

Аналогичный подход применялся в этом скрипте для создания "обратимого" транслита из кириллицы.

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

В PHP есть готовая функция substr_count, которую легко приспособить и для строки, прочитанной из файла:

<?php
 function file_substr_count ($path, $word) {
  if (file_exists($path) and is_file($path)) {
   $file = file_get_contents ($path);
   return substr_count ($file, $word);
  }
  return 0;
 }
 echo file_substr_count ('./text.txt','слово');
?>

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


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

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