<?php

function cms_do_stage($stage = '') {
    global $cms;
    if (!isset($cms['stages'][$stage]) || !is_array($cms['stages'][$stage]) || !empty($cms['stages'][$stage]['disabled'])) return; // disable warnings if stage disabled
    ksort($cms['stages'][$stage]);
    /*while(list($nice, $val) = each($cms['stages'][$stage])) {
        // skip 'next', 'disabled'
        if (is_array($cms['stages'][$stage][$nice]))
        while(list($forder,$function) = each($cms['stages'][$stage][$nice])) {
            $function();
        }
    }*/
    foreach ($cms['stages'][$stage] as $nice => $value) {
        # skip non numeric keys
        if (is_array($cms['stages'][$stage][$nice])) {
            foreach ( $cms['stages'][$stage][$nice] as $function => $enabled ) {
                if ( $enabled ) {
                    $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) {
        clearstatcache();
        if (function_exists('opcache_invalidate')) { opcache_invalidate($cms['config_file']); }
        include($cms['config_file']);
    }
    return $r;
}

// Создание нового этапа
// Вторым параметром указываем к какому перейти после этого
// Если ничего не указываем, то CMS завершит работу после него
function cms_add_stage($stage, $next = '') {
    global $cms;
    $cms['stages'][$stage]['next'] = $next;
}

// Вставка этапа
// Вставляет новый этап, между текущим и следующим
// Вторым параметром можно переназначить следующий
function cms_insert_stage($stage, $next = '') {
    global $cms;
    if ($next === '') $next = $cms['stages'][$cms['stage']]['next'];
    $cms['stages'][$stage]['next'] = $next;
}

// Добавление функции в этап
// По умолчанию приоритет 10
// Увеличивая приоритет, отодвигаем функцию в конец, уменьшая - вперед
function cms_add_function($stage, $function, $nice = 10) {
    global $cms;
    $cms['stages'][$stage][$nice][$function] = true;
    if ( !isset( $cms['stages'][$stage]['next'] ) ) { $cms['stages'][$stage]['next'] = ''; } /* fix warning */
}

// Удаление функции из этапа
/*
function cms_remove_function($stage, $function) {
    global $cms;
    foreach ($cms['stages'][$stage] as $nice => $value) {
        foreach ($cms['stages'][$stage][$nice] as $fn) {
            if ($fn === $function) {
                unset($cms['stages'][$stage][$nice][$fn]);
            }
        }
    }
}
*/

// $data['to_name']
// $data['to_email']
// $data['subject']
// $data['email_body']
// $data['from_name']
// $data['from_email']
// $data['files']
// $data['type'] (text/html(default) or text/plain)
// $data['sender'] if empty, then noreply@$_SERVER['SERVER_NAME']
// $data['bcc']
function cms_email($data) {
    global $images;

    $to_name = @trim($data['to_name']);
    if (!empty($to_name)) {
        $to = '=?utf-8?b?'.base64_encode($to_name).'?= <'.$data['to_email'].'>';
    } else {
        $to = $data['to_email'];
    }

    $subject = '=?utf-8?b?'.base64_encode($data['subject']).'?=';

    $from_name = @trim($data['from_name']);
    if (!empty($from_name)) {
        $from = '=?utf-8?b?'.base64_encode($from_name).'?= <'.$data['from_email'].'>';
    } else {
        $from = $data['from_email'];
    }

    $boundary = md5(uniqid(time()-25));
    $boundary_id = md5(uniqid(time()));

    if (empty($data['sender'])) { $sender = "noreply@{$_SERVER['SERVER_NAME']}"; } else { $sender = $data['sender']; }

    $headers = "Sender: $sender\r\nFrom: $from\r\nReply-To: $from\r\nContent-Type: multipart/mixed; boundary=\"$boundary\"\r\n";

    if (!empty($data['bcc'])) $headers .= "Bcc: {$data['bcc']}\r\n";

    $images = array();
    $body2 = preg_replace_callback('/<img +src="([^"]+)"/', 
        function($matches){
            $r2 = preg_replace_callback('/data:image\/(\w+);base64,(.+)/',
                function($matches){
                    global $images;
                    $n = count($images);
                    $images[$n] = array('ext'=>$matches[1], 'base64'=>$matches[2]);
                    return "cid:$n.".$matches[1];
                }, $matches[1]);
            return '<img src="'.$r2.'"';
        }, $data['email_body']
    );

    if (empty($data['type']) || $data['type'] === 'html') {
        $type = 'text/html';
    } else {
        $type = 'text/plain';
    }

    $body_all = "--$boundary\r\nContent-Type: multipart/related; boundary=\"$boundary_id\"\r\n\r\n";
    $body_all .= "--$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($images as $ind=>$image) {
        $body_all .= "--$boundary_id\r\nContent-Type: image/".$image['ext']."; name=\"$ind.".$image['ext']."\"\r\nContent-ID: <$ind.".$image['ext'].">\r\nContent-Disposition: inline; filename=\"$ind.".$image['ext']."\"\r\nContent-transfer-encoding: base64\r\n\r\n".chunk_split($image['base64'])."\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);
        $body_all .= "--$boundary_id\r\nContent-Type: $mime; name=\"$name\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment; filename=\"$name\"\r\n\r\n".chunk_split(base64_encode(file_get_contents($file)))."\r\n\r\n";
    }

    $body_all .= "--$boundary_id--\r\n\r\n";
    $body_all .= "--$boundary--\r\n\r\n";

    if ( mail($to, $subject, $body_all, $headers, "-f{$data['from_email']}") ) {
        return '';
    } else {
        return 'error';
    }
}

// $data['to_name']
// $data['to_email']
// $data['subject']
// $data['email_body']
// $data['from_name']
// $data['from_email']
// $data['files']
// $data['type'] (text/html(default) or text/plain)
// $data['sender'] if empty, then noreply@$_SERVER['SERVER_NAME']
// $data['bcc']
/* Возвращает пустую строку, если отправка успешна или строку ошибки, если нет. */
function cms_smtp_email($data) {
    global $images;

    $to_name = @trim($data['to_name']);
    if (!empty($to_name)) {
        $to = '=?utf-8?b?'.base64_encode($to_name).'?= <'.$data['to_email'].'>';
    } else {
        $to = $data['to_email'];
    }

    $from_name = @trim($data['from_name']);
    if (!empty($from_name)) {
        $from = '=?utf-8?b?'.base64_encode($from_name).'?= <'.$data['from_email'].'>';
    } else {
        $from = $data['from_email'];
    }

    $boundary = md5(uniqid(time()-25));
    $boundary_id = md5(uniqid(time()));

    if (empty($data['sender'])) {
        $sender = "noreply@{$_SERVER['SERVER_NAME']}";
    } else {
        $sender = $data['sender'];
    }
    
    if (empty($data['return_path'])) {
        $return_path = "noreply@{$_SERVER['SERVER_NAME']}";
    } 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: {$from}\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 .= "Content-Transfer-Encoding: 8bit\r\n";
    $SEND .= "\r\n";
    /* end headers */

    $images = array();
    $body2 = preg_replace_callback('/<img +src="([^"]+)"/', 
        function($matches){
            $r2 = preg_replace_callback('/data:image\/(\w+);base64,(.+)/',
                function($matches){
                    global $images;
                    $n = count($images);
                    $images[$n] = array('ext'=>$matches[1], 'base64'=>$matches[2]);
                    return "cid:$n.".$matches[1];
                }, $matches[1]);
            return '<img src="'.$r2.'"';
        }, $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($images as $ind=>$image) {
        $SEND .= "--{$boundary_id}\r\nContent-Type: image/{$image['ext']}; name=\"{$ind}.{$image['ext']}\"\r\nContent-ID: <{$ind}.{$image['ext']}>\r\nContent-Disposition: inline; filename=\"{$ind}.{$image['ext']}\"\r\nContent-transfer-encoding: base64\r\n\r\n".chunk_split($image['base64'])."\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\nContent-Type: {$mime}; name=\"{$name}\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment; filename=\"{$name}\"\r\n\r\n".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";

    if( !$data['socket'] = fsockopen( $data['smtp_host'], $data['smtp_port'], $errno, $errstr, 10 ) ) {
        return "{$errno}\n{$errstr}";
    }
 
	if ( substr( fgets( $data['socket'], 1000 ), 0, 3 ) != "220" ) { return "220"; }
 
    fputs( $data['socket'], "HELO {$data['smtp_host']}\r\n");
	if ( substr( $r = fgets( $data['socket'], 1000 ), 0, 3 ) != "250" ) {
		fclose( $data['socket'] );
		return "Не могу отправить HELO!";
    }
    
	fputs( $data['socket'], "AUTH LOGIN\r\n" );
	if ( substr( $r = fgets( $data['socket'], 1000 ), 0, 3 ) != "334" ) {
		fclose( $data['socket'] );
		return "Не могу найти ответ на запрос авторизаци.";
    }
    
	fputs( $data['socket'], base64_encode( $data['smtp_login'])."\r\n" );
	if ( substr( $r = fgets( $data['socket'], 1000 ), 0, 3 ) != "334" ) {
		fclose( $data['socket'] );
		return "Логин авторизации не был принят сервером!";
    }
    
	fputs( $data['socket'], base64_encode( $data['smtp_password'])."\r\n" );
	if ( substr( $r = fgets( $data['socket'], 1000 ), 0, 3 ) != "235" ) {
		fclose( $data['socket'] );
		return "Пароль не был принят сервером как верный!";
    }
    
	fputs( $data['socket'], "MAIL FROM: <{$data['smtp_login']}>\r\n" );
	if ( substr( $r = fgets( $data['socket'], 1000 ), 0, 3 ) != "250" ) {
		fclose($data['socket']);
		return "Не могу отправить комманду MAIL FROM";
    }
    
	fputs( $data['socket'], "RCPT TO: <{$data['to_email']}>\r\n" );
	if ( substr( $r = fgets( $data['socket'], 1000 ), 0, 3 ) != "250" ) {
		fclose($data['socket']);
		return "Не могу отправить комманду RCPT TO";
    }

    if ( !empty( $data['bcc'] ) ) {
        fputs( $data['socket'], "RCPT TO: {$data['bcc']}\r\n" );
        if ( substr( $r = fgets( $data['socket'], 1000 ), 0, 3 ) != "250" ) {
            fclose($data['socket']);
            return "Не могу отправить комманду RCPT TO (bcc)";
        }
    }
    
	fputs( $data['socket'], "DATA\r\n" );
	if ( substr( $r = fgets( $data['socket'], 1000 ), 0, 3 ) != "354" ) {
		fclose($data['socket']);
		return "Не могу отправить комманду DATA";
    }
    
	fputs( $data['socket'], "{$SEND}\r\n.\r\n" );
	if ( substr( $r = fgets( $data['socket'], 1000 ), 0, 3 ) != "250" ) {
		fclose($data['socket']);
		return "Не могу отправить тело письма.";
    }
    
	fputs( $data['socket'], "QUIT\r\n" );
	fclose( $data['socket'] );
	return "";
}

function cms_readfile($file) {
    if (file_exists($file)) {
        /*if (ob_get_level()) {
            ob_end_clean();
        }*/
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.basename($file).'"');
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file));
        @ob_clean();
        flush();
        if ( $fd = fopen( $file, 'rb' ) ) {
            while ( !feof( $fd ) ) {
              print fread( $fd, 1024 );
            }
            return fclose( $fd );
        } else {
            return false;
        }
        //return readfile($file); mem exhausted
    } else {
        return false;
    }
}

function __( $string, $module = "admin.mod.php" ) {
    global $cms;
    if ( !isset( $cms['config'] ) ) return $string;
    // Load lang file
    if ( !isset( $cms["lang"][$module][ $cms['config']['locale'] ] ) ) {
        $file = $cms['cms_dir'].'/lang/'.$cms['config']['locale'].'/'.$module;
        if ( file_exists( $file ) ) {
            include_once( $file );
        } else {
            $cms["lang"][$module][ $cms['config']['locale'] ] = array();
        }
    }
    // Translate
    if ( isset( $cms["lang"][$module][ $cms['config']['locale'] ][$string] ) ) {
        return $cms["lang"][$module][ $cms['config']['locale'] ][$string];
    } else {
        return $string;
    }
}

function cms_translit( $string ) {
    global $cms;
    $tr1 = strtr( $string, $cms['tr'] );
    $tr2 = strtr( $tr1, array(' '=>'-') );
    $tr3 = preg_replace('/[^-A-Za-z0-9_]+/u', '', $tr2);
    $tr4 = trim($tr3, '-_');
    return $tr4;
}

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;
}

function cms_asort( &$array ) {
    if ( !is_array( $array ) ) return false;
    return uasort( $array, 'cms_uasort' );
}

function cms_uasort( $a, $b ) {
    if ( !isset($a['sort']) || !isset($b['sort']) ) {
        return 0;
    }
    if ( $a['sort'] <= $b['sort'] ) {
        return -1;
    } else {
        return 1;
    }
}