<?php

/**
 * Vvveb
 *
 * Copyright (C) 2022  Ziadin Givan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

namespace Vvveb;



/**
 * Downloads content from a URL using cURL or file_get_contents.
 *
 * @param  string      $url The URL to download.
 * @return string|null The downloaded content, or null on failure.
 */

function download(string $url): ?string {
	$result = null;

	$url = html_entity_decode($url);
	$ips = validateUrl($url);

	if (! $ips) {
		return null;
	}

	if (function_exists('curl_init')) {
		$ch = curl_init($url);

		if ($ch) {
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($ch, CURLOPT_RESOLVE, $ips);
			curl_setopt($ch, CURLOPT_FAILONERROR, true);
			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
			curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT'] ?? 'Vvveb ' . V_VERSION);
			$result   = curl_exec($ch);
			$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

			if (PHP_MAJOR_VERSION < 8) {
				curl_close($ch);
			}

			if ($httpcode != 200) {
				return null;
			}
		}
	} else {
		if (ini_get('allow_url_fopen') == '1') {
			$context_options = [
				'http' => [
					'timeout'       => 5,
					'ignore_errors' => 1,
				],
			];
			$context  = stream_context_create($context_options);
			$result   = @file_get_contents($url, 'r', $context) ?: null;
		}
	}

	return $result;
}



/**
 * Fetches URL content with caching support.
 *
 * @param  string $url       The URL to fetch.
 * @param  bool   $cache     Whether to cache the result (default true).
 * @param  int    $expire    Cache expiration in seconds (default 604800).
 * @param  int    $timeout   Request timeout in seconds (default 5).
 * @param  bool   $exception Whether to throw exceptions on failure (default true).
 * @return mixed  The fetched content, or null on failure.
 */

function getUrl(string $url, bool $cache = true, int $expire = 604800, int $timeout = 5, bool $exception = true): mixed {
	$cacheDriver  = System\Cache :: getInstance();
	$cacheKey     = md5($url);
	$result       = false;

	$ips = validateUrl($url);

	if (! $ips) {
		return null;
	}

	if ($cache && ($result = $cacheDriver->get('url', $cacheKey))) {
		return $result;
	} else {
		$result = false;
		$url    = html_entity_decode($url);
		//try with curl
		if (function_exists('curl_init')) {
			$ch = curl_init($url);

			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($ch, CURLOPT_RESOLVE, $ips);
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
			curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
			curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT'] ?? 'Vvveb ' . V_VERSION);

			if (DEBUG) {
				curl_setopt($ch, CURLOPT_VERBOSE, true);
				$streamVerboseHandle = fopen('php://temp', 'w+');
				curl_setopt($ch, CURLOPT_STDERR, $streamVerboseHandle);
			}

			$result = curl_exec($ch);

			if ($result) {
				$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
				if ($httpcode != 200) {
					return null;
				}

				if ($cache) {
					$cacheDriver->set('url', $cacheKey, $result);
				}

				return $result;
			} else {
				if ($exception) {
					$message = 'Curl error: ' . curl_errno($ch) . ' - ' . curl_error($ch);

					if (DEBUG) {
						$message .= "\n" . print_r(curl_getinfo($ch), 1);
						rewind($streamVerboseHandle);
						$message .= "\n" . stream_get_contents($streamVerboseHandle);
					}

					throw new \Exception($message);
				}
			}

			if (PHP_MAJOR_VERSION < 8) {
				curl_close($ch);
			}
		} else {
			//try with file get contents
			if (ini_get('allow_url_fopen') == '1') {
				$context_options = [
					'http' => [
						'timeout'       => $timeout,
						'ignore_errors' => 1,
					],
				];

				$context         = stream_context_create($context_options);

				if ($exception) {
					$result = file_get_contents($url, false, $context);
				} else {
					$result = @file_get_contents($url, false, $context);
				}
			}

			if ($result) {
				if ($cache) {
					$cacheDriver->set('url', $cacheKey, $result);
				}

				return $result;
			}
		}
	}

	return $result;
}

