/** * Generate a PDF Document on the fly from a piece of HTML code. * * Notice: this is using a secured cache folder, unique per visitor ID * * @param STRING $y_html_content :: The HTML Code * @param ENUM $y_orientation :: Page Orientation: 'normal' | 'wide' * @param STRING $y_runtime_script :: The allowed Runtime Script to allow send credentials for sub-downloads. Ex: admin.php * @param STRING $y_runtime_url :: The allowed Runtime URL ended by '/' to allow send credentials for sub-downloads. Ex: http(s)://some-server/some_path/ ; normally this should be set in config to enforce https:// and a single URL only * @param BOOLEAN $y_allow_send_credentials :: Set to TRUE to allow or set to FALSE to dissalow sending the auth credentials for sub-downloads: in the case there are embedded pictures generated by admin.php which may need authentication before to work, the credentials need to be set automatically in this case * * @returns STRING :: The PDF Document Contents * */ public static function generate($y_html_content, $y_orientation = 'normal', $y_runtime_script = '', $y_runtime_url = '', $y_allow_send_credentials = false) { //-- $pdfdata = ''; //-- $htmldoc = self::is_active(); //-- if ((string) $htmldoc != '') { //-- if ((string) $y_orientation == 'wide') { $orientation = self::tag_page_wide(); } else { $orientation = self::tag_page_normal(); } //end if else //-- $tmp_prefix_dir = 'tmp/cache/pdf/'; $protect_file = $tmp_prefix_dir . '.htaccess'; $dir = $tmp_prefix_dir . SMART_FRAMEWORK_SESSION_PREFIX . '/'; // we use different for index / admin / @ //-- $uniquifier = SmartUtils::unique_auth_client_private_key() . SMART_APP_VISITOR_COOKIE; $the_dir = $dir . Smart::safe_varname(Smart::uuid_10_seq() . '_' . Smart::uuid_10_num() . '_' . SmartHashCrypto::sha1($uniquifier)) . '/'; //-- $tmp_uuid = Smart::uuid_45($uniquifier) . Smart::uuid_36($uniquifier); $file = $the_dir . '__document_' . SmartHashCrypto::sha256('@@PDF#File::Cache@@' . $tmp_uuid) . '.html'; $logfile = $the_dir . '__headers_' . SmartHashCrypto::sha256('@@PDF#File::Cache@@' . $tmp_uuid) . '.log'; //-- if (is_dir($the_dir)) { SmartFileSystem::dir_delete($the_dir); } //end if //-- if (!is_dir($the_dir)) { SmartFileSystem::dir_recursive_create($the_dir); } // end if //-- SmartFileSystem::write_if_not_exists($protect_file, trim(SMART_FRAMEWORK_HTACCESS_FORBIDDEN) . "\n", 'yes'); //-- process the code $y_html_content = (string) self::remove_between_tags((string) $y_html_content); $y_html_content = (string) self::safe_charset((string) $y_html_content); //-- extract images $htmlparser = new SmartHtmlParser((string) $y_html_content); $arr_imgs = $htmlparser->get_tags('img'); $htmlparser = ''; unset($htmlparser); //-- $chk_duplicates_arr = array(); //-- for ($i = 0; $i < Smart::array_size($arr_imgs); $i++) { //-- $tmp_img_src = trim((string) $arr_imgs[$i]['src']); //-- if (strlen($chk_duplicates_arr[$tmp_img_src]) <= 0) { //-- $tmp_url_img_src = ''; //-- if ((string) $y_runtime_script != '' and (string) $y_runtime_url != '') { // replace relative paths if (substr($tmp_img_src, 0, @strlen($y_runtime_script)) == (string) $y_runtime_script) { $tmp_url_img_src = (string) $y_runtime_url . $tmp_img_src; $y_html_content = (string) @str_replace('src="' . $tmp_img_src . '"', 'src="' . $tmp_url_img_src . '"', (string) $y_html_content); $tmp_img_src = (string) $tmp_url_img_src; } //end if } //end if //-- $tmp_img_ext = '.' . strtolower(SmartFileSysUtils::get_file_extension_from_path($tmp_img_src)); // [OK] $tmp_img_cache = 'pdf_img_' . SmartHashCrypto::sha256('@@PDF#File::Cache::IMG@@' . '#' . $i . '@' . $tmp_img_src . '//' . $tmp_uuid); //-- $tmp_arr = array(); //-- if (substr($tmp_img_src, 0, 7) == 'http://' or substr($tmp_img_src, 0, 8) == 'https://') { //-- $tmp_img_ext = ''; // we clear the extension as we don't know yet (we will get it from headers) $tmp_img_cache = 'pdf_url_img_' . SmartHashCrypto::sha256('@@PDF#File::Cache::URL::IMG@@' . '#' . $i . '@' . $tmp_img_src . '//' . $tmp_uuid); //-- } //end if //-- if ($y_allow_send_credentials === true) { $allow_set_credentials = 'yes'; } else { $allow_set_credentials = 'no'; } //end if else //-- $tmp_arr = SmartUtils::load_url_or_file($tmp_img_src, SMART_FRAMEWORK_NETSOCKET_TIMEOUT, 'GET', '', '', '', $allow_set_credentials); // [OK] :: allow set credentials //-- $tmp_img_ext = '.noextension'; $tmp_where_we_guess = ''; //-- $guess_arr = array(); //-- $guess_arr = SmartUtils::guess_image_extension_by_url_head($tmp_arr['headers']); $tmp_img_ext = (string) $guess_arr['extension']; $tmp_where_we_guess = (string) $guess_arr['where-was-detected']; $guess_arr = array(); if ((string) $tmp_img_ext == '') { $tmp_img_ext = SmartUtils::guess_image_extension_by_first_bytes(substr($tmp_arr['content'], 0, 256)); if ((string) $tmp_img_ext != '') { $tmp_where_we_guess = ' First Bytes ...'; } //end if } //end if //-- if ((string) SMART_FRAMEWORK_DEBUG_MODE == 'yes') { // if debug, append information to log SmartFileSystem::write($logfile, '####################' . "\n" . '#################### [FILE # ' . $i . ' = \'' . $tmp_img_src . '\']' . "\n\n" . '==== [MODE] :: ' . $tmp_arr['mode'] . "\n" . '==== [LOG] :: ' . "\n" . $tmp_arr['log'] . "\n" . '==== [HEADERS] ::' . "\n" . $tmp_arr['headers'] . "\n" . '########' . "\n" . '==== [GUESS EXTENSION] :: ' . $tmp_where_we_guess . "\n\n" . '###################' . "\n\n\n\n", 'a'); } //end if //-- if ((string) $tmp_arr['result'] == '1' and (string) $tmp_arr['code'] == '200') { //-- SmartFileSystem::write($the_dir . $tmp_img_cache . $tmp_img_ext, $tmp_arr['content']); //-- if empty, it may be a file if ((string) $tmp_img_ext == '' or (string) $tmp_img_ext == '.png' or (string) $tmp_img_ext == '.gif' or (string) $tmp_img_ext == '.jpg') { $y_html_content = (string) @str_replace('src="' . $tmp_img_src . '"', 'src="' . $tmp_img_cache . $tmp_img_ext . '"', (string) $y_html_content); } else { // we want to avoid html code to be loaded as image by mistakes of http browser class or servers $y_html_content = (string) @str_replace('src="' . $tmp_img_src . '"', 'src="' . $y_runtime_url . 'lib/framework/img/sign_warn.png"', (string) $y_html_content); } //end if else //-- } else { //-- $y_html_content = (string) @str_replace('src="' . $tmp_img_src . '"', 'src="' . $y_runtime_url . 'lib/framework/img/sign_error.png"', (string) $y_html_content); //-- } //end if //-- } //end if //-- $chk_duplicates_arr[$tmp_img_src] = 'processed'; //-- } //end for //-- $chk_duplicates_arr = array(); unset($chk_duplicates_arr); $arr_imgs = array(); unset($arr_imgs); //-- SmartFileSystem::write($file, $orientation . "\n" . $y_html_content); //-- if (is_file($file)) { //-- ob_start(); //-- @passthru($htmldoc . ' ' . self::pdf_options($file)); //-- $pdfdata = ob_get_clean(); //-- } else { //-- Smart::log_warning('ERROR: PDF Generator Failed to find the PDF Document: ' . $file . "\n" . $y_html_content); //-- } //end if else //-- cleanup if ((string) SMART_FRAMEWORK_DEBUG_MODE != 'yes') { // if not debug, cleanup the dir if (is_dir($the_dir)) { SmartFileSystem::dir_delete($the_dir); } //end if } //end if //-- } else { //-- Smart::log_notice('NOTICE: PDF Generator is INACTIVE ...'); //-- } //end if //-- return (string) $pdfdata; //-- }
public static final function DownloadsHandler($encrypted_download_pack, $controller_key) { //-- $encrypted_download_pack = (string) $encrypted_download_pack; $controller_key = (string) $controller_key; //-- $client_signature = SmartUtils::get_visitor_signature(); //-- if ((string) SMART_APP_VISITOR_COOKIE == '') { Smart::log_info('File Download', 'Failed: 400 / Invalid Visitor Cookie' . ' on Client: ' . $client_signature); self::Raise400Error('ERROR: Invalid Visitor UUID. Cookies must be enabled to enable this feature !'); return ''; } //end if //-- $downloaded_file = ''; // init //-- $decoded_download_packet = (string) trim((string) SmartUtils::crypto_decrypt((string) $encrypted_download_pack, 'SmartFramework//DownloadLink' . SMART_FRAMEWORK_SECURITY_KEY)); //-- if ((string) $decoded_download_packet != '') { // if data is corrupted, decrypt checksum does not match, will return an empty string //-- if (SMART_FRAMEWORK_ADMIN_AREA === true) { // {{{SYNC-DWN-CTRL-PREFIX}}} $controller_key = (string) 'AdminArea/' . $controller_key; } else { $controller_key = (string) 'IndexArea/' . $controller_key; } //end if //-- {{{SYNC-DOWNLOAD-ENCRYPT-ARR}}} $arr_metadata = explode("\n", (string) $decoded_download_packet, 6); // only need first 5 parts //print_r($arr_metadata); // #PACKET-STRUCTURE# [we will have an array like below, according with the: SmartUtils::create_download_link()] // [TimedAccess]\n // [FilePath]\n // [AccessKey]\n // [UniqueKey]\n // [SFR.UA]\n // #END# //-- $crrtime = (string) trim((string) $arr_metadata[0]); $filepath = (string) trim((string) $arr_metadata[1]); $access_key = (string) trim((string) $arr_metadata[2]); $unique_key = (string) trim((string) $arr_metadata[3]); //-- unset($arr_metadata); //-- $timed_hours = 1; // default expire in 1 hour if (defined('SMART_FRAMEWORK_DOWNLOAD_EXPIRE')) { if ((int) SMART_FRAMEWORK_DOWNLOAD_EXPIRE > 0) { if ((int) SMART_FRAMEWORK_DOWNLOAD_EXPIRE <= 24) { // max is 24 hours (since download link is bind to unique browser signature + unique cookie ... make non-sense to keep more) $timed_hours = (int) SMART_FRAMEWORK_DOWNLOAD_EXPIRE; } //end if } //end if } //end if //-- if ((int) $timed_hours > 0) { if ((int) $crrtime < (int) (time() - 60 * 60 * $timed_hours)) { Smart::log_info('File Download', 'Failed: 403 / Download expired at: ' . date('Y-m-d H:i:s O', (int) $crrtime) . ' for: ' . $filepath . ' on Client: ' . $client_signature); self::Raise403Error('ERROR: The Access Key for this Download is Expired !'); return ''; } //end if } //end if //-- if ((string) $access_key != (string) sha1('DownloadLink:' . SMART_SOFTWARE_NAMESPACE . '-' . SMART_FRAMEWORK_SECURITY_KEY . '-' . SMART_APP_VISITOR_COOKIE . ':' . $filepath . '^' . $controller_key)) { Smart::log_info('File Download', 'Failed: 403 / Invalid Access Key for: ' . $filepath . ' on Client: ' . $client_signature); self::Raise403Error('ERROR: Invalid Access Key for this Download !'); return ''; } //end if //-- if ((string) $unique_key != (string) SmartHashCrypto::sha1('Time=' . $crrtime . '#' . SMART_SOFTWARE_NAMESPACE . '-' . SMART_FRAMEWORK_SECURITY_KEY . '-' . $access_key . '-' . SmartUtils::unique_auth_client_private_key() . ':' . $filepath . '+' . $controller_key)) { Smart::log_info('File Download', 'Failed: 403 / Invalid Client (Unique) Key for: ' . $filepath . ' on Client: ' . $client_signature); self::Raise403Error('ERROR: Invalid Client Key to Access this Download !'); return ''; } //end if //-- if (SmartFileSysUtils::check_file_or_dir_name($filepath)) { //-- $skip_log = 'no'; // default log if (defined('SMART_FRAMEWORK_DOWNLOAD_SKIP_LOG')) { $skip_log = 'yes'; // do not log if accessed via admin area and user is authenticated } //end if //-- $tmp_file_ext = (string) strtolower(SmartFileSysUtils::get_file_extension_from_path($filepath)); // [OK] $tmp_file_name = (string) strtolower(SmartFileSysUtils::get_file_name_from_path($filepath)); //-- $tmp_eval = SmartFileSysUtils::mime_eval($tmp_file_name); $mime_type = (string) $tmp_eval[0]; $mime_disp = (string) $tmp_eval[1]; //-- the path must not start with / but this is tested below $tmp_arr_paths = (array) explode('/', $filepath, 2); // only need 1st part for testing //-- allow file downloads just from specific folders like wpub/ or wsys/ (this is a very important security fix to dissalow any downloads that are not in the specific folders) if (substr((string) $filepath, 0, 1) != '/' and strpos((string) SMART_FRAMEWORK_DOWNLOAD_FOLDERS, '<' . trim((string) $tmp_arr_paths[0]) . '>') !== false and stripos((string) SMART_FRAMEWORK_DENY_UPLOAD_EXTENSIONS, '<' . $tmp_file_ext . '>') === false) { //-- SmartFileSysUtils::raise_error_if_unsafe_path($filepath); // re-test finally //-- @clearstatcache(); //-- if (is_file($filepath)) { //-- if (!headers_sent()) { //-- $fp = @fopen($filepath, 'rb'); $fsize = @filesize($filepath); //-- if (!$fp || $fsize <= 0) { //-- Smart::log_info('File Download', 'Failed: 404 / The requested File is Empty or Not Readable: ' . $filepath . ' on Client: ' . $client_signature); self::Raise404Error('WARNING: The requested File is Empty or Not Readable !'); return ''; //-- } //end if //-- set max execution time to zero ini_set('max_execution_time', 0); // we can expect a long time if file is big, but this will be anyway overriden by the WebServer Timeout Directive //-- // cache headers are presumed to be sent by runtime before of this step //-- header('Content-Type: ' . $mime_type); header('Content-Disposition: ' . $mime_disp); header('Content-Length: ' . $fsize); //-- @fpassthru($fp); // output without reading all in memory //-- @fclose($fp); //-- } else { //-- Smart::log_info('File Download', 'Failed: 500 / Headers Already Sent: ' . $filepath . ' on Client: ' . $client_signature); self::Raise500Error('ERROR: Download Failed, Headers Already Sent !'); return ''; //-- } //end if else //-- if ((string) $skip_log != 'yes') { //-- $downloaded_file = (string) $filepath; // return the file name to be logged //-- } //end if //-- } else { //-- Smart::log_info('File Download', 'Failed: 404 / The requested File does not Exists: ' . $filepath . ' on Client: ' . $client_signature); self::Raise404Error('WARNING: The requested File for Download does not Exists !'); return ''; //-- } //end if else } else { //-- Smart::log_info('File Download', 'Failed: 403 / Access to this File is Denied: ' . $filepath . ' on Client: ' . $client_signature); self::Raise403Error('ERROR: Download Access to this File is Denied !'); return ''; //-- } //end if else //-- } else { //-- Smart::log_info('File Download', 'Failed: 400 / Unsafe File Path: ' . $filepath . ' on Client: ' . $client_signature); self::Raise400Error('ERROR: Unsafe Download File Path !'); return ''; //-- } //end if else //-- } else { //-- Smart::log_info('File Download', 'Failed: 400 / Invalid Data Packet' . ' on Client: ' . $client_signature); self::Raise400Error('ERROR: Invalid Download Data Packet !'); return ''; //-- } //end if else //-- return (string) $downloaded_file; //-- }
public static function decode_mime_fileurl($y_enc_msg_file, $y_ctrl_key) { //-- $y_enc_msg_file = (string) trim((string) $y_enc_msg_file); if ((string) $y_enc_msg_file == '') { Smart::log_warning('Mail-Utils / Decode Mime File URL: Empty Message File Path has been provided. This means the URL link will be unavaliable (empty) to assure security protection.'); return ''; } //end if if (!SmartFileSysUtils::check_file_or_dir_name($y_enc_msg_file)) { Smart::log_warning('Mail-Utils / Decode Mime File URL: Invalid Message File Path has been provided. This means the URL link will be unavaliable (empty) to assure security protection. Message File: ' . $y_enc_msg_file); return ''; } //end if //-- $y_ctrl_key = (string) trim((string) $y_ctrl_key); if ((string) $y_ctrl_key == '') { Smart::log_warning('Mail-Utils / Decode Mime File URL: Empty Controller Key has been provided. This means the URL link will be unavaliable (empty) to assure security protection.'); return ''; } //end if if (SMART_FRAMEWORK_ADMIN_AREA === true) { // {{{SYNC-ENCMIMEURL-CTRL-PREFIX}}} $y_ctrl_key = (string) 'AdminMailUtilArea/' . $y_ctrl_key; } else { $y_ctrl_key = (string) 'IndexMailUtilArea/' . $y_ctrl_key; } //end if //-- $the_sep_arr = (array) self::mime_separe_part_link($y_enc_msg_file); $y_enc_msg_file = (string) $the_sep_arr['msg']; $the_msg_part = (string) $the_sep_arr['part']; unset($the_sep_arr); //-- $arr = array(); // {{{SYNC-MIME-ENCRYPT-ARR}}} $arr['error'] = ''; // by default, no error //-- if ((string) SMART_APP_VISITOR_COOKIE == '') { $arr['error'] = 'WARNING: Access Forbidden ... No Visitor ID set ...!'; return (array) $arr; } //end if //-- if ((string) $the_msg_part != '') { $the_msg_part = strtolower(trim((string) SmartUtils::url_hex_decode((string) $the_msg_part))); } //end if //-- $decoded_link = trim((string) SmartUtils::crypto_decrypt((string) $y_enc_msg_file, 'SmartFramework//MimeLink' . SMART_FRAMEWORK_SECURITY_KEY)); $dec_arr = (array) explode("\n", trim((string) $decoded_link)); //print_r($dec_arr); //-- $arr['creation-time'] = trim((string) $dec_arr[0]); $arr['message-file'] = trim((string) $dec_arr[1]); $arr['message-part'] = trim((string) $the_msg_part); $arr['access-key'] = trim((string) $dec_arr[2]); $arr['bw-unique-key'] = trim((string) $dec_arr[3]); $arr['sf-robot-key'] = trim((string) $dec_arr[4]); //-- check if file path is valid if ((string) $arr['message-file'] == '') { $arr = array(); $arr['error'] = 'ERROR: Empty Message Path ...'; return (array) $arr; } //end if if (!SmartFileSysUtils::check_file_or_dir_name($arr['message-file'])) { $arr = array(); $arr['error'] = 'ERROR: Unsafe Message Path Access ...'; return (array) $arr; } //end if //-- $browser_os_ip_identification = SmartUtils::get_os_browser_ip(); // get browser and os identification //-- re-compose the access key $crrtime = (int) $arr['creation-time']; $access_key = sha1('MimeLink:' . SMART_SOFTWARE_NAMESPACE . '-' . SMART_FRAMEWORK_SECURITY_KEY . '-' . SMART_APP_VISITOR_COOKIE . ':' . $arr['message-file'] . '>' . $y_ctrl_key); $uniq_key = sha1('Time=' . $crrtime . '#' . SMART_SOFTWARE_NAMESPACE . '-' . SMART_FRAMEWORK_SECURITY_KEY . '-' . $access_key . '-' . SmartUtils::unique_auth_client_private_key() . ':' . $arr['message-file'] . '>' . $y_ctrl_key); $self_robot_key = sha1('Time=' . $crrtime . '#' . SmartAuth::get_login_id() . '*' . SMART_SOFTWARE_NAMESPACE . '-' . SMART_FRAMEWORK_SECURITY_KEY . '-' . trim($browser_os_ip_identification['signature']) . '$' . $access_key . ':' . $arr['message-file'] . '>' . $y_ctrl_key); //-- check access key if ((string) $arr['error'] == '') { if ((string) $access_key != (string) $arr['access-key']) { $arr = array(); $arr['error'] = 'ERROR: Access Forbidden ... Invalid ACCESS KEY ...'; } //end if } //end if //-- check the client key if ((string) $arr['error'] == '') { //-- $ok_client_key = false; //-- if ((string) $the_msg_part == '' and (string) $arr['bw-unique-key'] == (string) $uniq_key) { // no message part, allow only client browser $ok_client_key = true; } elseif ((string) $the_msg_part != '' and ((string) $arr['bw-unique-key'] == (string) $uniq_key or (string) $browser_os_ip_identification['bw'] == '@s#' and (string) $arr['sf-robot-key'] == (string) $self_robot_key)) { $ok_client_key = true; } else { $ok_client_key = false; } //end if else //-- if ($ok_client_key != true) { $arr = array(); $arr['error'] = 'ERROR: Access Forbidden ... Invalid CLIENT KEY ...'; } //end if //-- } //end if //-- return (array) $arr; //-- }