$val) { if($val[$field] == $value) { return $val; } } return $default_value; } /** * Search for the key of the first item with value $value for field $field in a 2D array. * @return The matching key or -1 */ function multiarray_search_key($field, $value, $array) { foreach($array as $key=>$val) { if($val[$field] == $value) { return $key; } } return -1; } /** * Filters a 2D array returning all the entries where $field is not equal to $value. * @return The filtered array. */ function multiarray_filter($field, $value, $array) { $return = array(); foreach($array as $key=>$val) { if($val[$field] != $value) { $return[] = $val; } } return $return; } /** * Check that $haystack starts with $needle. */ function startswith($haystack, $needle) { $length = strlen($needle); return (substr($haystack, 0, $length) === $needle); } /** * Check that $haystack ends with $needle. */ function endswith($haystack, $needle) { $length = strlen($needle); if ($length == 0) { return true; } return (substr($haystack, -$length) === $needle); } /** * Replace only the first occurrence of $needle in $haystack by $replace. */ function str_replace_first($needle, $replace, $haystack) { $pos = strpos($haystack, $needle); if ($pos !== false) { $newstring = substr_replace($haystack, $replace, $pos, strlen($needle)); } } /** * List all available templates. * @return An array {path, name, current} where path is the template path, name is the template name and current is true if this is the current template, false otherwise. */ function list_templates() { global $config; $paths = array_filter(scandir(TPL_DIR), function($item) { return is_dir(TPL_DIR.$item) && !startswith($item, '.'); }); $names = array_map('ucfirst', $paths); $templates = array(); foreach($paths as $key=>$path) { $path .= '/'; $templates[] = array( 'path'=>$path, 'name'=>$names[$key], 'current'=>$path == $config->template ); } return $templates; } /** * Get the total generation time. * @param $start_generation_time is a milliseconds timestamp * @return Generation time as a string, with units (seconds or milliseconds) */ function get_generation_time($start_generation_time) { $round = round(microtime(true) - (float)$start_generation_time, 2).'s'; if($round == '0s') { $round = round((microtime(true) - $start_generation_time)*1000, 3).'ms'; } return $round; } /** * Returns the global category of a MIME-TYPE * @param $mime_type, a MIME-TYPE */ function get_category_mime_type($mime_type) { $end = strpos($mime_type, '/'); if ($end === false) { return false; } $category = substr($mime_type, 0, $end); $available_categories = array('application', 'audio', 'example', 'image', 'message', 'model', 'multipart', 'text', 'video'); $end = in_array($category, $available_categories); if ($end !== false) { return $category; } else { return false; } } /** * Downloads all the urls in the array $urls and returns an array with the results and the http status_codes. * * Mostly inspired by blogotext by timovn : https://github.com/timovn/blogotext/blob/master/inc/fich.php * * Note: If open_basedir or safe_mode, Curl will not follow redirections : * https://stackoverflow.com/questions/24687145/curlopt-followlocation-and-curl-multi-and-safe-mode * * @param an array $urls of associative arrays {'url', 'post'} for each URL. 'post' is a JSON array of data to send _via_ POST. * @return an array {'results', 'status_code'}, results being an array of the retrieved contents, indexed by URLs, and 'status_codes' being an array of status_code, indexed by URL. */ function curl_downloader($urls, $fetch_content=true, $verbose=true) { $chunks = array_chunk($urls, 40, true); // Chunks of 40 urls because curl has problems with too big "multi" requests $results = array(); $status_codes = array(); $content_types = array(); $command_line = is_command_line(); if (ini_get('open_basedir') == '' && ini_get('safe_mode') === false) { // Disable followlocation option if this is activated, to avoid warnings $follow_redirect = true; } else { $follow_redirect = false; } if ($verbose) { if (function_exists('apache_setenv')) { /* Selon l'hébergeur la fonction peut être désactivée. Alors Php arrête le programme avec l'erreur : "PHP Fatal error: Call to undefined function apache_setenv()". */ @apache_setenv('no-gzip', 1); } @ini_set('zlib.output_compression', 0); @ini_set('implicit_flush', 1); for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); } ob_implicit_flush(1); if ($command_line) { $backspace = PHP_EOL; $span_start = ''; $span_end = ''; } else { $backspace = '
'; $span_start = ''; $span_end = ''; } } foreach ($chunks as $chunk) { $multihandler = curl_multi_init(); $handlers = array(); $total_feed_chunk = count($chunk) + count($results); foreach ($chunk as $i=>$url_array) { set_time_limit(20); // Reset max execution time $url = $url_array['url']; $handlers[$i] = curl_init($url); curl_setopt_array($handlers[$i], array( CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 15, CURLOPT_FOLLOWLOCATION => $follow_redirect, CURLOPT_MAXREDIRS => 5, CURLOPT_USERAGENT => (!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''), // Add a user agent to prevent problems with some feeds CURLOPT_HEADER => $fetch_content ? FALSE : TRUE, CURLOPT_NOBODY => $fetch_content ? FALSE : TRUE, )); if (!empty($url_array['post'])) { curl_setopt($handlers[$i], CURLOPT_POST, true); curl_setopt($handlers[$i], CURLOPT_POSTFIELDS, json_decode($url_array['post'], true)); } if ($verbose) { echo str_replace('CLASS', 'class="refreshed-feed-tmp"', $span_start).'Starting to download '.$url.'…'.$backspace.$span_end; } curl_multi_add_handle($multihandler, $handlers[$i]); } do { curl_multi_exec($multihandler, $active); curl_multi_select($multihandler); } while ($active > 0); if ($verbose && !$command_line) { echo ''; } foreach ($chunk as $i=>$url_array) { $url = $url_array['url']; $results[$url] = curl_multi_getcontent($handlers[$i]); $status_codes[$url] = curl_getinfo($handlers[$i], CURLINFO_HTTP_CODE); $content_types[$url] = curl_getinfo($handlers[$i], CURLINFO_CONTENT_TYPE); curl_multi_remove_handle($multihandler, $handlers[$i]); curl_close($handlers[$i]); if ($verbose && !$command_line) { echo str_replace('CLASS', '', $span_start).'Starting to download '.$url.'… Done.'.$backspace.$span_end; } } curl_multi_close($multihandler); } return array('results'=>$results, 'status_codes'=>$status_codes, 'content_types'=>$content_types); } /** * Clean the rainTPL cache * @param (optional) $folder, folder with the rainTPL cache, default to tmp */ function clean_cache($folder='tmp/') { $folder_handler = opendir(ROOT_DIR.$folder); while ($file = readdir($folder_handler)) { if ($file == '.' || $file == '..') { continue; } unlink(ROOT_DIR.$folder.'/'.$file); } closedir($folder_handler); } /** * Check if the script is run from the command line or not * @return true if script is run from command line, false otherwise */ function is_command_line() { return 'cli' == php_sapi_name(); } /** * Check if url_rewriting is available * @return 1 if available, 0 otherwise */ function get_url_rewriting() { if (function_exists('apache_get_modules')) { return (int) in_array('mod_rewrite', apache_get_modules()); } else { return getenv('HTTP_MOD_REWRITE')=='On' ? 1 : 0; } } /** * Check if curl is available * @return null or an array of disabled functions. */ function check_curl_availability() { $curl_functions = array( 'curl_multi_init', 'curl_init', 'curl_setopt_array', 'curl_setopt', 'curl_multi_add_handle', 'curl_multi_exec', 'curl_multi_select', 'curl_multi_getcontent', 'curl_getinfo', 'curl_multi_remove_handle', 'curl_close', 'curl_multi_close' ); $curl_disabled_functions = array(); foreach($curl_functions as $curl_function) if (! function_exists ($curl_function)) $curl_disabled_functions[] = $curl_function; if (count ($curl_disabled_functions) > 0) return $curl_disabled_functions; return null; } /** * Check if pdo_sqlite is available * @return true if available, false otherwise */ function is_pdo_sqlite_available() { return in_array('pdo_sqlite', get_loaded_extensions()); } /** * Format date for pretty printing * @param $timestamp: date in timestamp format. */ function format_date($timestamp) { $now = time(); $diff = $now - $timestamp; if ($diff < 60) { return $diff.'s ago'; } else if ($diff < 300) { return round($diff / 60).'min ago'; } else if ($diff < 3600) { return (round($diff / 300) * 5).'min ago'; } else if (floor($now/86400) == floor($timestamp/86400)) { return 'Today, '.date('H:i', $timestamp); } else if (floor($now/86400) == floor($timestamp/86400) + 1) { return 'Yesterday, '.date('H:i', $timestamp); } else if (date('Y:W', $now) == date('Y:W', $timestamp)) { return date('l, H:i', $timestamp); } else if (date('Y',$now) == date('Y',$timestamp)) { return date('F d, H:i', $timestamp); } else { return date('F d, Y, H:i', $timestamp); } }