PHP скрипт. Simple URL checker — выполнение проверок (cURL)

Владимир | | PHP, Web разработка.

Simple URL checker - cURL
Приветствую всех!

Как я и обещал, мы продолжаем разработку приложения для проверки URL и сегодня займемся непосредственно выполнением проверок.

Чтобы немного облегчить себе жизнь, проверки мы будем выполнять с помощью библиотеки cURL.

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

Теперь нам нужно подключить эту библиотеку к PHP. Для этого в файле php.ini нужно убрать «;» в начале строки extension=php_curl.dll. После этого в сведениях, которые возвращает функция phpinfo() появится раздел curl и в нем параметр — cURL support: enabled.

Библиотека подключена и можно начинать ее использовать.

Для начала приведу небольшой пример, иллюстрирующий основные принципы работы с библиотекой на PHP.

$ch = curl_init();    // инициализация
curl_setopt($ch, CURLOPT_URL, ‘http://www.google.com’); // устанавливаем URL
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// разрешаем редирект
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // указывает, что функция curl_exec должна вернуть полученный ответ, а не отправить его сразу браузеру
$result = curl_exec($ch); // запуск
curl_close($ch);
echo $result;

Здесь все достаточно просто. Функция curl_init инициализирует библиотеку и создает объект для работы с ней ($ch). После этого с помощью функции curl_setopt можно настроить библиотеку. В первом параметре этой функции передаем созданный объект, во втором – указываем имя параметра, который нужно настроить, а в третьем – значение параметра.

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

Возвращаемся к нашему приложению.

Как я и говорил в прошлый раз, всю работу по проверке URL выполняет метод ping. Рассмотрим его подробнее.

function ping($urlId = 0) {
	$this->load->model('urlmodel');
	$this->load->model('resultmodel');
	$urls = array();
	if ($urlId == 0) {
		//получаем полный список URL из БД
		$urls = $this->urlmodel->getAllUrls();
	}
	else {
		//ищем выбранный URL
		$urls = $this->urlmodel->getUrlById($urlId);
	}
	if ($urls !== FALSE) {
		//создаем обработчик для параллельной работы с URL'ами
		$mh = curl_multi_init();
		//создаем обработчики для каждого отдельного URL и добавляем их в $mh
		$handles = array();
		for ($i = 0; $i < count($urls); $i++) {
			$handles[$i] = curl_init();
			curl_setopt($handles[$i], CURLOPT_URL, $urls[$i]['URL']);
			curl_setopt($handles[$i], CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($handles[$i], CURLOPT_FOLLOWLOCATION, 1);
			curl_setopt($handles[$i], CURLOPT_TIMEOUT, 10);
			curl_setopt($handles[$i], CURLOPT_HEADER, 0);
			//если используется прокси, нужно указать его порт и ip
			//curl_setopt($handles[$i], CURLOPT_PROXYPORT, "8080");
			//curl_setopt($handles[$i], CURLOPT_PROXY, "192.168.0.1");

			curl_multi_add_handle($mh, $handles[$i]);
		}
		//запускаем обработку
		$running = null;
		do {
			curl_multi_exec($mh, $running);
		} while ($running > 0);
		//получаем данные и сохраняем их в БД
		for ($i = 0; $i < count($urls); $i++) {
			$urlInfo = curl_getinfo($handles[$i]);
			$resData['urlId'] = $urls[$i]['id'];
			if ($urlInfo['speed_download'] != 0) {
				$resData['result'] = 1;
			}
			else {
				$resData['result'] = 0;
			}
			$resData['responsetime'] = $urlInfo['total_time'];
			$resData['responselength'] = $urlInfo['size_download'];
			$resData['responsespeed'] = $urlInfo['speed_download'];
			$this->resultmodel->saveResults($resData);
		}
		//закрываем обработчики
		for ($i = 0; $i < count($handles); $i++) {
			curl_multi_remove_handle($mh, $handles[$i]);
		}
		if ($urlId == 0) {
			$this->index();
		}
		else {
			$this->urldetails($urlId);
		}
	}
}

Как видите, метод довольно объемный и достаточно сильно отличается от первого примера. Но обо всем по порядку.

После загрузки моделей, мы проверяем значение параметра $urlId. Если он равен нулю, то выполняем проверку всех URL в базе данных, если нет – проверяем только заданный URL.

Теперь нам нужно проверить найденные в базе данных URL. Если этот URL один, то все довольно просто, можно ограничиться кодом из первого примера, но у нас может быть несколько десятков URL. Запустить проверки в цикле, конечно, возможно, но это скрипт при этом может выполняться довольно долго. А в большинстве случаев время работы скриптов ограничено (параметр max_execution_time).

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

После этого в цикле (строки 18-30) с помощью curl_init мы создаем массив объектов для работы с каждым URL, настраиваем его и с помощью функции curl_multi_add_handle добавляем в контейнер (строка 29).

Обратите внимание на параметр CURLOPT_TIMEOUT (строка 23). Я установил его равным 10 секундам. Это время в течении которого cURL будет ждать ответ сервера. Значение я взял «с потолка», поэтому если оно вас не устраивает, можете спокойно его изменить.

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

Функция curl_multi_exec вызывается внутри цикла, выход из которого выполняется, когда переменная $running будет равна нулю, т.е. завершится обработка всех URL.

После этого нам остается только получить данные о проверках с помощью функции curl_getinfo (строка 38) и сформировать массив с результатами ($resData).

На завершающем этапе мы сохраняем данные в БД (строка 49), с помощью функции curl_multi_remove_handle закрываем обработчики (строка 53) и показываем посетителю страницу, с которой был вызван метод (строки 55-60).

Все. Метод для выполнения проверок готов. В следующий раз мы рассмотрим создание представлений, т.е. страниц сайта.

До встречи!

P.S. Ссылки на все статьи и примеры цикла я публикую здесь.