Mercurial
view .cms/index.fn.php @ 1:1d486627aa1e draft default tip
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Sat, 12 Oct 2024 02:51:39 +0000 |
parents | |
children |
line wrap: on
line source
<?php // Add function to selected hook with default priority 10 function hook_add_fn( $hook, $function, $priority = 10 ) { global $cms; $cms["hooks"][$hook][$priority][$function] = true; // true - enabled // fix warning if ( ! isset( $cms["hooks"][$hook]["next"] ) ) { $cms["hooks"][$hook]["next"] = ""; } } function do_hook( $hook = "" ) { global $cms; if ( empty( $cms["hooks"][$hook] ) || ! empty( $cms["hooks"][$hook]["disabled"] ) ) { return; } ksort( $cms["hooks"][$hook] ); foreach ( $cms["hooks"][$hook] as $priority => &$value ) { if ( is_array( $cms["hooks"][$hook][$priority] ) ) { foreach ( $cms["hooks"][$hook][$priority] as $function => &$enabled ) { if ( $enabled && function_exists( $function ) ) { $function(); } } } } } function cms_save_config() { global $cms; $r = file_put_contents( $cms["config_file"], '<?php $cms["config"] = ' . var_export( $cms["config"], true) . ";\n", LOCK_EX ); if ( $r && function_exists( "opcache_invalidate" ) ) { opcache_invalidate( $cms["config_file"] ); } return $r; } #region Функции отправки письма - это комментарий для схлопывания всех фукнций письма function cms_email_callback2( $matches ) { global $email_images; $n = count( $email_images ); $email_images[$n] = array( "ext" => $matches[1], "base64" => $matches[2] ); return "cid:{$n}.{$matches[1]}"; } function cms_email_callback1( $matches ) { $r2 = preg_replace_callback( "/data:image\/(\w+);base64,(.+)/u", "cms_email_callback2", $matches[1] ); return "<img src=\"$r2\""; } // $data["to_name"] // $data["to_email"] // $data["subject"] // $data["email_body"] // $data["from_name"] // $data["from_email"] // $data["reply_name"] // $data["reply_to"] // $data["files"] // $data["type"] ( text/html or text/plain (default) ) // $data["sender"] if empty, then noreply@$_SERVER["SERVER_NAME"] // $data["bcc"] // return "" if success of "error:..." if error function cms_email( $data ) { global $email_images; // На пустую to_email не надо проверять, потому что возможна рассылка через скрытые копии if ( isset( $data["to_name"] ) ) { $to = "=?utf-8?b?" . base64_encode( $data["to_name"] ) . "?= <" . $data["to_email"] . ">"; } else { $to = $data["to_email"]; } $subject = "=?utf-8?b?" . base64_encode( $data["subject"] ) . "?="; if ( isset( $data["from_name"] ) ) { $from = "=?utf-8?b?" . base64_encode( $data["from_name"] ) . "?= <" . $data["from_email"] . ">"; } else { $from = $data["from_email"]; } if ( empty( $data["reply_to"] ) ) { $reply = $from; } else { $reply = $data["reply_to"]; if ( ! empty( $data["reply_name"] ) ) { $reply = "=?utf-8?b?" . base64_encode( $data["reply_name"] ) . "?= <" . $data["reply_to"] . ">"; } } $boundary = md5( uniqid( time() - 25 ) ); $boundary_id = md5( uniqid( time() ) ); if ( empty( $data["sender"] ) ) { $sender = "noreply@{$_SERVER['SERVER_NAME']}"; } else { $sender = $data["sender"]; } $headers = ""; $headers .= "Sender: {$sender}\r\n"; $headers .= "From: {$from}\r\n"; $headers .= "Reply-To: {$reply}\r\n"; $headers .= "Content-Type: multipart/mixed; boundary=\"{$boundary}\"\r\n"; if ( ! empty( $data["bcc"] ) ) { $headers .= "Bcc: {$data['bcc']}\r\n"; } $email_images = array(); $body2 = preg_replace_callback( '/<img\s[^>]*src="([^"]+)"/u', "cms_email_callback1", $data["email_body"] ); if ( empty( $data["type"] ) ) { $type = "text/plain"; } else { $type = $data["type"]; } $body_all = ""; $body_all .= "--{$boundary}\r\n"; $body_all .= "Content-Type: multipart/related; boundary=\"{$boundary_id}\"\r\n"; $body_all .= "\r\n"; $body_all .= "--{$boundary_id}\r\n"; $body_all .= "Content-Type: {$type}; charset=utf-8;\r\n"; $body_all .= "Content-Transfer-Encoding: base64\r\n"; $body_all .= "\r\n"; $body_all .= chunk_split( base64_encode( $body2 ) ) . "\r\n"; $body_all .= "\r\n"; foreach( $email_images as $ind => $image ) { $body_all .= "--{$boundary_id}\r\n"; $body_all .= "Content-Type: image/{$image['ext']}; name=\"{$ind}.{$image['ext']}\"\r\n"; $body_all .= "Content-ID: <{$ind}.{$image['ext']}>\r\n"; $body_all .= "Content-Disposition: inline; filename=\"{$ind}.{$image['ext']}\"\r\n"; $body_all .= "Content-transfer-encoding: base64\r\n"; $body_all .= "\r\n"; $body_all .= chunk_split( $image["base64"] ) . "\r\n"; $body_all .= "\r\n"; } if ( isset( $data["files"] ) && is_array( $data["files"] ) ) foreach( $data["files"] as $file ) { $mime = mime_content_type( $file ); $name = preg_replace( "/.*\//u", "", $file ); $body_all .= "--{$boundary_id}\r\n"; $body_all .= "Content-Type: {$mime}; name=\"{$name}\"\r\n"; $body_all .= "Content-Transfer-Encoding: base64\r\n"; $body_all .= "Content-Disposition: attachment; filename=\"{$name}\"\r\n"; $body_all .= "\r\n"; $body_all .= chunk_split( base64_encode( file_get_contents( $file ) ) ) . "\r\n"; $body_all .= "\r\n"; } $body_all .= "--{$boundary_id}--\r\n"; $body_all .= "\r\n"; $body_all .= "--{$boundary}--\r\n"; $body_all .= "\r\n"; if ( mail( $to, $subject, $body_all, $headers, "-f{$data['from_email']}" ) ) { return ""; } else { return "error mail() function"; } } // $data["to_name"] // $data["to_email"] // $data["subject"] // $data["email_body"] // $data["from_name"] // $data["from_email"] // $data["reply_name"] // $data["reply_to"] // $data["files"] // $data["type"] ( text/plain (default) or text/html ) // $data["sender"] if empty, then noreply@$_SERVER["SERVER_NAME"] // $data["bcc"] // $data["smtp_host"] // $data["smtp_port"] // $data["smtp_login"] // $data["smtp_password"] // return "" if success of "error:..." if error function cms_smtp_email( $data ) { global $email_images, $cms; if ( isset( $data["to_name"] ) ) { $to = "=?utf-8?b?" . base64_encode( $data["to_name"] ) . "?= <" . $data["to_email"] . ">"; } else { $to = $data["to_email"]; } if ( isset( $data["from_name"] ) ) { $from = "=?utf-8?b?" . base64_encode( $data["from_name"] ) . "?= <" . $data["from_email"] . ">"; } else { $from = $data["from_email"]; } if ( empty( $data["reply_to"] ) ) { $reply = $from; } else { $reply = $data["reply_to"]; if ( ! empty( $data["reply_name"] ) ) { $reply = "=?utf-8?b?" . base64_encode( $data["reply_name"] ) . "?= <" . $data["reply_to"] . ">"; } } $boundary = md5( uniqid( time() - 25 ) ); $boundary_id = md5( uniqid( time() ) ); if ( empty( $data["sender"] ) ) { $sender = $data["from_email"]; } else { $sender = $data["sender"]; } if ( empty( $data["return_path"] ) ) { $return_path = $data["from_email"]; } else { $return_path = $data["return_path"]; } /* start headers */ $SEND = "Date: " . date( "r" ) . "\r\n"; $SEND .= "Sender: {$sender}\r\n"; $SEND .= "Return-Path: {$return_path}\r\n"; $SEND .= "Reply-To: {$reply}\r\n"; $SEND .= "From: {$from}\r\n"; $SEND .= "To: {$to}\r\n"; if ( ! empty( $data["bcc"] ) ) { $SEND .= "Bcc: {$data['bcc']}\r\n"; } $SEND .= "Subject: =?utf-8?b?" . base64_encode( $data["subject"] ) . "?=\r\n"; $SEND .= "Content-Type: multipart/mixed; boundary=\"{$boundary}\"\r\n"; $SEND .= "\r\n"; /* end headers */ /* Move images to appendix */ $email_images = array(); $body2 = preg_replace_callback( '/<img +src="([^"]+)"/u', "cms_email_callback1", $data["email_body"] ); if ( empty( $data["type"] ) ) { $type = "text/plain"; } else { $type = $data["type"]; } $SEND .= "--{$boundary}\r\nContent-Type: multipart/related; boundary=\"{$boundary_id}\"\r\n\r\n"; $SEND .= "--{$boundary_id}\r\nContent-Type: {$type}; charset=utf-8;\r\nContent-Transfer-Encoding: base64\r\n\r\n" . chunk_split( base64_encode( $body2 ) ) . "\r\n\r\n"; foreach( $email_images as $ind => $image ) { $SEND .= "--{$boundary_id}\r\n"; $SEND .= "Content-Type: image/{$image['ext']}; name=\"{$ind}.{$image['ext']}\"\r\n"; $SEND .= "Content-ID: <{$ind}.{$image['ext']}>\r\n"; $SEND .= "Content-Disposition: inline; filename=\"{$ind}.{$image['ext']}\"\r\n"; $SEND .= "Content-transfer-encoding: base64\r\n\r\n"; $SEND .= chunk_split( $image['base64'] ); $SEND .= "\r\n\r\n"; } if ( isset( $data["files"] ) && is_array( $data["files"] ) ) { foreach( $data["files"] as $file ) { $mime = mime_content_type( $file ); $name = preg_replace( "/.*\//u", "", $file ); $SEND .= "--{$boundary_id}\r\n"; $SEND .= "Content-Type: {$mime}; name=\"{$name}\"\r\n"; $SEND .= "Content-Transfer-Encoding: base64\r\n"; $SEND .= "Content-Disposition: attachment; filename=\"{$name}\"\r\n\r\n"; $SEND .= chunk_split( base64_encode( file_get_contents( $file ) ) ) . "\r\n\r\n"; } } $SEND .= "--{$boundary_id}--\r\n\r\n"; $SEND .= "--{$boundary}--\r\n\r\n"; $debug_file = "{$cms['cms_dir']}/smtp_debug.txt"; cms_debug( $debug_file, "\n---" ); // Connect cms_debug( $debug_file, "fsockopen {$data['smtp_host']} {$data['smtp_port']}" ); $socket = fsockopen( $data["smtp_host"], $data["smtp_port"], $errno, $errstr, 10 ); // 10 sec timeout if( $socket === false ) { cms_debug( $debug_file, "fsockopen error {$errno} {$errstr}" ); return "{$errno} {$errstr}"; } cms_debug( $debug_file, "fsockopen ok" ); stream_set_timeout( $socket, 3 ); // Receive data after connection $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( substr( $r, 0, 3 ) === "220" ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { return $r; } // HELLO cms_debug( $debug_file, "ME: EHLO {$_SERVER['SERVER_NAME']}" ); fputs( $socket, "EHLO {$_SERVER['SERVER_NAME']}\r\n"); // Receive data after HELLO $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( preg_match( '/250.AUTH/', $r ) ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { fclose( $socket ); cms_debug( $debug_file, "The server does not greet us." ); return $r."\nThe server does not greet us."; } // AUTH cms_debug( $debug_file, "ME: AUTH LOGIN" ); fputs( $socket, "AUTH LOGIN\r\n" ); // Receive data $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( substr( $r, 0, 3 ) === "334" ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { fclose( $socket ); cms_debug( $debug_file, "Can't find the answer to the authorization request." ); return "Can't find the answer to the authorization request."; } // Send login cms_debug( $debug_file, "ME: base64_encode( smtp_login )" ); fputs( $socket, base64_encode( $data["smtp_login"] ) . "\r\n" ); // Receive data $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( substr( $r, 0, 3 ) === "334" ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { fclose( $socket ); cms_debug( $debug_file, "The authorization login was not accepted by the server." ); return "The authorization login was not accepted by the server."; } // Send password cms_debug( $debug_file, "ME: base64_encode( smtp_password )" ); fputs( $socket, base64_encode( $data["smtp_password"] ) . "\r\n" ); // Receive data $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( substr( $r, 0, 3 ) === "235" ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { fclose( $socket ); cms_debug( $debug_file, "The password was not accepted by the server as correct." ); return "The password was not accepted by the server as correct."; } // Send FROM cms_debug( $debug_file, "ME: MAIL FROM: <{$data['from_email']}>" ); fputs( $socket, "MAIL FROM: <{$data['from_email']}>\r\n" ); // Receive data $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( substr( $r, 0, 3 ) === "250" ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { fclose( $socket ); cms_debug( $debug_file, "Can't send command MAIL FROM" ); return "Can't send command MAIL FROM"; } // Send recipient cms_debug( $debug_file, "ME: RCPT TO: <{$data['to_email']}>" ); fputs( $socket, "RCPT TO: <{$data['to_email']}>\r\n" ); // Receive data $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( substr( $r, 0, 3 ) === "250" ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { fclose( $socket ); cms_debug( $debug_file, "Can't send RCPT TO command" ); return "Can't send RCPT TO command"; } // BCC if ( ! empty( $data["bcc"] ) ) { cms_debug( $debug_file, "ME (bcc): RCPT TO: <{$data['bcc']}>" ); fputs( $socket, "RCPT TO: {$data['bcc']}\r\n" ); // Receive data $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( substr( $r, 0, 3 ) === "250" ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { fclose( $socket ); cms_debug( $debug_file, "Can't send RCPT TO (bcc) command" ); return "Can't send RCPT TO (bcc) command"; } } // Email body command cms_debug( $debug_file, "ME: DATA" ); fputs( $socket, "DATA\r\n" ); // Receive data $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( substr( $r, 0, 3 ) === "354" ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { fclose( $socket ); cms_debug( $debug_file, "Can't send DATA command" ); return "Can't send DATA command"; } // Send email body cms_debug( $debug_file, "ME SEND DATA" ); fputs( $socket, "{$SEND}\r\n.\r\n" ); // Receive data $ok = false; while ( $r = fgets( $socket, 1000 ) ) { cms_debug( $debug_file, "SERVER: {$r}" ); if ( substr( $r, 0, 3 ) === "250" ) { $ok = true; } if ( substr( $r, 3, 1 ) === " " ) { break; } } if ( $ok === false ) { fclose( $socket ); cms_debug( $debug_file, "I can not send the body of the letter." ); return "I can not send the body of the letter."; } // Quit command cms_debug( $debug_file, "ME: QUIT\n" ); fputs( $socket, "QUIT\r\n" ); fclose( $socket ); return ""; } #endregion Функции отправки письма function cms_debug( $debug_file, $string ) { global $cms; if ( empty( $cms["config"]["debug"] ) ) { return; } // Следим за размером файла if ( is_file( $debug_file ) && filesize( $debug_file ) > 16384 ) { rename( $debug_file, $debug_file . ".old" ); } // Сбрасываем инфу if ( substr( $string, -1 ) !== "\n" ) { $string .= "\n"; } file_put_contents( $debug_file, $string, FILE_APPEND ); } // Функция для отправки файла браузеру малыми порциями, // чтобы не было ошибок с закончившейся памятью function cms_readfile( $file, $headers = true ) { if ( file_exists( $file ) ) { /* if (ob_get_level()) { ob_end_clean(); } */ if ( $headers ) { header( "Content-Description: File Transfer" ); $mime = mime_content_type( $file ); header( "Content-Type: {$mime}" ); $basename = basename( $file ); header( "Content-Disposition: attachment; filename=\"{$basename}\"" ); header( "Content-Transfer-Encoding: binary" ); header( "Expires: 0" ); header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" ); header( "Pragma: public" ); $filesize = filesize( $file ); header( "Content-Length: {$filesize}" ); ob_clean(); flush(); } if ( $handle = fopen( $file, "rb" ) ) { while ( ! feof( $handle ) ) { print fread( $handle, 1024 ); } return fclose( $handle ); } else { return false; } } else { return false; } } // Принимает строку, которую нужно перевести // и модуль ("page.mod.php") если нужно дернуть перевод из другого function __( $string, $module = "" ) { global $cms; // Определяем вызвавший файл $backtrace = debug_backtrace(); $basename = pathinfo( $backtrace[0]["file"], PATHINFO_BASENAME ); $basedir = basename( pathinfo( $backtrace[0]["file"], PATHINFO_DIRNAME ) ); if ( $module === "" ) { $module = $basename; // Автовыбор модуля для шаблона админки if ( $basedir === "admin.cms" && $basename === "html.php" ) { $module = "admin.mod.php"; } } // Загрузка файла перевода если еще не загружен if ( ! isset( $cms["lang"][$module][ $cms["config"]["locale"] ] ) ) { $file = $cms["cms_dir"] . "/lang/" . $cms["config"]["locale"] . "/" . $module; if ( is_file( $file ) ) { include_once( $file ); } else { $cms["lang"][$module][ $cms["config"]["locale"] ] = array(); } // load translit if ( ! isset( $cms["tr"] ) ) $cms["tr"] = array(); $translit = $cms["cms_dir"] . "/lang/" . $cms["config"]["locale"] . "/translit.php"; if ( is_file( $translit ) ) { include_once( $translit ); } } // Translate if ( isset( $cms["lang"][$module][ $cms["config"]["locale"] ][$string] ) ) { return $cms["lang"][$module][ $cms["config"]["locale"] ][$string]; } else { // Чтобы узнать какие переводы отсутствуют, нужно включить отладку в config.php // $cms["config"]["debug"] = true; // Результаты буду в файле .cms/debug.log.php if ( ! empty( $cms["config"]["debug"] ) && empty( $cms["debug"]["translate"][$string] ) ) { $line = $backtrace[0]["line"]; $t = "translate to {$cms["config"]["locale"]}"; $f = "{$basename}:{$line}"; $cms["debug"][$t][$f] = $string; } return $string; } } function cms_translit( $string, $trim_dash = true ) { global $cms; $tr1 = strtr( $string, $cms["tr"] ); $tr2 = strtr( $tr1, array( " " => "-" ) ); $tr3 = preg_replace( "/[^-A-Za-z0-9_]+/u", "", $tr2 ); if ( $trim_dash ) { $tr3 = trim( $tr3, "-_" ); } return $tr3; } function cms_translit_file( $string ) { global $cms; $tr1 = strtr( $string, $cms["tr"] ); $tr2 = strtr( $tr1, array( " " => "_" ) ); $tr3 = preg_replace( "/[^-A-Za-z0-9_]+/u", "", $tr2 ); return $tr3; } // Вспомогательная функция для последующей cms_asort() function cms_uasort( $a, $b ) { if ( ! isset( $a["sort"] ) || ! isset( $b["sort"] ) ) { return 0; } if ( $a["sort"] <= $b["sort"] ) { return -1; } else { return 1; } } // Сортирует массив из элементов, которые тоже являются массивами // и содержат ключ sort function cms_asort( &$array ) { if ( ! is_array( $array ) ) return false; return uasort( $array, "cms_uasort" ); } // Рекурсивное удаление папок function recurse_rm( $src ) /* bool */ { if ( ! is_dir( $src ) ) { return false; } $dir = opendir( $src ); // readdir может вернуть аналог false, поэтому строгая проверка while( false !== ( $file = readdir( $dir ) ) ) { if ( ( $file != "." ) && ( $file != ".." ) ) { if ( is_dir( "{$src}/{$file}" ) ) { recurse_rm( "{$src}/{$file}" ); } else { if ( ! unlink( "{$src}/{$file}" ) ) { return false; } } } } closedir( $dir ); return rmdir( $src ); } function is_email( $str ) { return preg_match( "/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,9})(\]?)$/", $str ); } // Returns a file size limit in bytes based on the PHP upload_max_filesize // and post_max_size function file_upload_max_size() { $max_size = -1; if ( $max_size < 0 ) { // Start with post_max_size. $post_max_size = parse_size( ini_get( "post_max_size" ) ); if ( $post_max_size > 0 ) { $max_size = $post_max_size; } // If upload_max_size is less, then reduce. Except if upload_max_size is // zero, which indicates no limit. $upload_max = parse_size( ini_get( "upload_max_filesize" ) ); if ( $upload_max > 0 && $upload_max < $max_size ) { $max_size = $upload_max; } } return $max_size; } function parse_size( $size ) { $unit = preg_replace( "/[^bkmgtpezy]/i", "", $size ); // Remove the non-unit characters from the size. $size = preg_replace( "/[^0-9\.]/", "", $size ); // Remove the non-numeric characters from the size. if ( $unit ) { // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by. return round( $size * pow( 1024, stripos( "bkmgtpezy", $unit[0] ) ) ); } else { return round( $size ); } } // Возвращает true только если это пустая папка function is_dir_and_empty( $dir ) { if ( ! is_dir( $dir ) ) { return false; } $handle = opendir( $dir ); while ( false !== ( $entry = readdir( $handle ) ) ) { if ( $entry != "." && $entry != ".." ) { closedir( $handle ); return false; } } closedir( $handle ); return true; } // Генерация uid для всяких нужд function cms_admin_pass_gen( $count = 8 ) { $chars = "0123456789AaBbCcDdEeFfGgHhiJjKkLMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; $strlen = strlen( $chars ) - 1; $password = ""; while ( $count-- ) { $password .= $chars[ rand( 0, $strlen ) ]; } return $password; } // Генерация uid для всяких нужд function cms_uid( $count = 8 ) { $chars = "0123456789AaBbCcDdEeFfGgHhiJjKkLMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; $strlen = strlen( $chars ) - 1; $password = ""; while ( $count-- ) { $password .= $chars[ rand( 0, $strlen ) ]; } return $password; }