diff .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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.cms/index.fn.php	Sat Oct 12 02:51:39 2024 +0000
@@ -0,0 +1,720 @@
+<?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;
+}
\ No newline at end of file