diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 938956a87..cd44c0340 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: PHP Lint & Codeception on: [ push, pull_request ] jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index 1d5dcc37c..e1edbf63c 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -2879,14 +2879,10 @@ class Context { return isset(self::$_instance->meta_tags[$name]) ? self::$_instance->meta_tags[$name]['content'] : null; } - - $ret = array(); - foreach(self::$_instance->meta_tags as $name => $content) + else { - $ret[] = array('name' => $name, 'is_http_equiv' => $content['is_http_equiv'], 'content' => escape($content['content'], false)); + return array_values(self::$_instance->meta_tags); } - - return $ret; } /** @@ -2894,14 +2890,17 @@ class Context * * @param string $name name of meta tag * @param string $content content of meta tag - * @param mixed $is_http_equiv value of http_equiv + * @param bool $is_http_equiv + * @param bool $is_before_title * @return void */ - public static function addMetaTag($name, $content, $is_http_equiv = false) + public static function addMetaTag($name, $content, $is_http_equiv = false, $is_before_title = true) { self::$_instance->meta_tags[$name] = array( + 'name' => $name, + 'content' => escape(self::replaceUserLang($content, true), false), 'is_http_equiv' => (bool)$is_http_equiv, - 'content' => self::replaceUserLang($content, true), + 'is_before_title' => (bool)$is_before_title, ); } diff --git a/classes/display/HTMLDisplayHandler.php b/classes/display/HTMLDisplayHandler.php index 52e5f697d..4622d803f 100644 --- a/classes/display/HTMLDisplayHandler.php +++ b/classes/display/HTMLDisplayHandler.php @@ -196,6 +196,12 @@ class HTMLDisplayHandler Context::set('favicon_url', $favicon_url); Context::set('mobicon_url', $mobicon_url); + // Only print the X-UA-Compatible meta tag if somebody is still using IE + if (preg_match('!Trident/7\.0!', $_SERVER['HTTP_USER_AGENT'] ?? '')) + { + Context::addMetaTag('X-UA-Compatible', 'IE=edge', true); + } + return $output; } @@ -641,7 +647,7 @@ class HTMLDisplayHandler { if ($tag !== '') { - Context::addOpenGraphData('og:article:tag', $tag, false); + Context::addOpenGraphData('og:article:tag', $tag); } } @@ -683,21 +689,21 @@ class HTMLDisplayHandler function _addTwitterMetadata() { $card_type = $this->_image_type === 'document' ? 'summary_large_image' : 'summary'; - Context::addMetaTag('twitter:card', $card_type); + Context::addMetaTag('twitter:card', $card_type, false, false); foreach(Context::getOpenGraphData() as $val) { if ($val['property'] === 'og:title') { - Context::addMetaTag('twitter:title', $val['content']); + Context::addMetaTag('twitter:title', $val['content'], false, false); } if ($val['property'] === 'og:description') { - Context::addMetaTag('twitter:description', $val['content']); + Context::addMetaTag('twitter:description', $val['content'], false, false); } if ($val['property'] === 'og:image' && $this->_image_type === 'document') { - Context::addMetaTag('twitter:image', $val['content']); + Context::addMetaTag('twitter:image', $val['content'], false, false); } } } diff --git a/classes/module/ModuleHandler.class.php b/classes/module/ModuleHandler.class.php index 7d518befa..95c535c3d 100644 --- a/classes/module/ModuleHandler.class.php +++ b/classes/module/ModuleHandler.class.php @@ -693,7 +693,8 @@ class ModuleHandler extends Handler } } - if ($kind === 'admin') { + if ($kind === 'admin') + { Context::addMetaTag('robots', 'noindex'); } diff --git a/common/defaults/config.php b/common/defaults/config.php index f28768d7c..8351d0056 100644 --- a/common/defaults/config.php +++ b/common/defaults/config.php @@ -151,5 +151,7 @@ return array( ], 'use_rewrite' => true, 'use_sso' => false, - 'other' => array(), + 'other' => [ + 'proxy' => null, + ], ); diff --git a/common/framework/HTTP.php b/common/framework/HTTP.php index 51e0b79ce..1948dee49 100644 --- a/common/framework/HTTP.php +++ b/common/framework/HTTP.php @@ -209,9 +209,10 @@ class HTTP ]; // Add proxy settings. - if (defined('__PROXY_SERVER__')) + $proxy = config('other.proxy') ?: (defined('__PROXY_SERVER__') ? constant('__PROXY_SERVER__') : ''); + if ($proxy !== '') { - $proxy = parse_url(constant('__PROXY_SERVER__')); + $proxy = parse_url($proxy); $proxy_scheme = preg_match('/^(https|socks)/', $proxy['scheme'] ?? '') ? ($proxy['scheme'] . '://') : 'http://'; $proxy_auth = (!empty($proxy['user']) && !empty($proxy['pass'])) ? ($proxy['user'] . ':' . $proxy['pass'] . '@') : ''; $settings['proxy'] = sprintf('%s%s%s:%s', $proxy_scheme, $proxy_auth, $proxy['host'], $proxy['port']); diff --git a/common/framework/drivers/mail/mailfunction.php b/common/framework/drivers/mail/mailfunction.php index 6e11d03c2..545031106 100644 --- a/common/framework/drivers/mail/mailfunction.php +++ b/common/framework/drivers/mail/mailfunction.php @@ -7,15 +7,6 @@ namespace Rhymix\Framework\Drivers\Mail; */ class MailFunction extends Base implements \Rhymix\Framework\Drivers\MailInterface { - /** - * Direct invocation of the constructor is not permitted. - */ - protected function __construct() - { - include_once \RX_BASEDIR . 'common/libraries/swift_mail.php'; - $this->_mailer = new \Swift_Mailer(new \Swift_MailTransport); - } - /** * Get the human-readable name of this mail driver. * @@ -58,6 +49,12 @@ class MailFunction extends Base implements \Rhymix\Framework\Drivers\MailInterfa */ public function send(\Rhymix\Framework\Mail $message) { + if ($this->_mailer === null) + { + include_once \RX_BASEDIR . 'common/libraries/swift_mail.php'; + $this->_mailer = new \Swift_Mailer(new \Swift_MailTransport); + } + try { $errors = []; diff --git a/common/framework/drivers/mail/smtp.php b/common/framework/drivers/mail/smtp.php index a15f05f68..7a762b2a9 100644 --- a/common/framework/drivers/mail/smtp.php +++ b/common/framework/drivers/mail/smtp.php @@ -7,23 +7,6 @@ namespace Rhymix\Framework\Drivers\Mail; */ class SMTP extends Base implements \Rhymix\Framework\Drivers\MailInterface { - /** - * Direct invocation of the constructor is not permitted. - */ - protected function __construct(array $config) - { - $security = in_array($config['smtp_security'], ['ssl', 'tls']) ? $config['smtp_security'] : null; - $transport = new \Swift_SmtpTransport($config['smtp_host'], $config['smtp_port'], $security); - $transport->setUsername($config['smtp_user']); - $transport->setPassword($config['smtp_pass']); - $local_domain = $transport->getLocalDomain(); - if (preg_match('/^\*\.(.+)$/', $local_domain, $matches)) - { - $transport->setLocalDomain($matches[1]); - } - $this->mailer = new \Swift_Mailer($transport); - } - /** * Get the list of configuration fields required by this mail driver. * @@ -56,9 +39,32 @@ class SMTP extends Base implements \Rhymix\Framework\Drivers\MailInterface */ public function send(\Rhymix\Framework\Mail $message) { + if ($this->_mailer === null) + { + if (isset($this->_config['smtp_security']) && in_array($this->_config['smtp_security'], ['ssl', 'tls'])) + { + $security = $this->_config['smtp_security']; + } + else + { + $security = null; + } + + $transport = new \Swift_SmtpTransport($this->_config['smtp_host'], $this->_config['smtp_port'], $security); + $transport->setUsername($this->_config['smtp_user']); + $transport->setPassword($this->_config['smtp_pass']); + $local_domain = $transport->getLocalDomain(); + if (preg_match('/^\*\.(.+)$/', $local_domain, $matches)) + { + $transport->setLocalDomain($matches[1]); + } + $this->_mailer = new \Swift_Mailer($transport); + } + try { - $result = $this->mailer->send($message->message, $errors); + $errors = []; + $result = $this->_mailer->send($message->message, $errors); } catch(\Exception $e) { diff --git a/common/framework/drivers/sms/apistore.php b/common/framework/drivers/sms/apistore.php deleted file mode 100644 index 2b294a0a5..000000000 --- a/common/framework/drivers/sms/apistore.php +++ /dev/null @@ -1,141 +0,0 @@ - 500, - 'sms_max_length' => 90, - 'sms_max_length_in_charset' => 'CP949', - 'lms_supported' => true, - 'lms_supported_country_codes' => array(82), - 'lms_max_length' => 2000, - 'lms_max_length_in_charset' => 'CP949', - 'lms_subject_supported' => true, - 'lms_subject_max_length' => 60, - 'mms_supported' => false, - 'delay_supported' => true, - ); - - /** - * Config keys used by this driver are stored here. - */ - protected static $_required_config = array('api_user', 'api_key'); - - /** - * Check if the current SMS driver is supported on this server. - * - * This method returns true on success and false on failure. - * - * @return bool - */ - public static function isSupported() - { - return true; - } - - /** - * Store the last response. - */ - protected $_last_response = ''; - - /** - * Send a message. - * - * This method returns true on success and false on failure. - * - * @param array $messages - * @param object $original - * @return bool - */ - public function send(array $messages, \Rhymix\Framework\SMS $original) - { - $status = true; - - foreach ($messages as $i => $message) - { - $data = array(); - $data['send_phone'] = $message->from; - $data['dest_phone'] = implode(',', $message->to); - $data['msg_body'] = strval($message->content); - if ($message->type !== 'SMS' && $message->subject) - { - $data['subject'] = $message->subject; - } - - $result = $this->_apiCall(sprintf('message/%s', strtolower($message->type)), $data); - if (!$result) - { - $message->errors[] = 'ApiStore API returned invalid response: ' . $this->_getLastResponse(); - $status = false; - } - if ($result->result_message !== 'OK') - { - $message->errors[] = 'ApiStore API error: ' . $result->result_code . ' ' . $result->result_message; - } - } - - return $status; - } - - /** - * API call. - * - * @param string $url - * @param array $data - * @param string $method (optional) - * @return object|false - */ - protected function _apiCall(string $url, array $data, string $method = 'POST') - { - // Build the request URL. - if ($data['version']) - { - $version = $data['version']; - unset($data['version']); - } - else - { - $version = 1; - } - $url = sprintf('http://api.apistore.co.kr/ppurio/%d/%s/%s', $version, trim($url, '/'), $this->_config['api_user']); - - // Set the API key in the header. - $headers = array( - 'x-waple-authorization' => $this->_config['api_key'], - ); - - // Send the API reqeust. - if ($method === 'GET') - { - if ($data) - { - $url .= '?' . http_build_query($data); - } - $this->_last_response = \FileHandler::getRemoteResource($url, null, 5, $method, null, $headers) ?: ''; - } - else - { - $this->_last_response = \FileHandler::getRemoteResource($url, $data, 5, $method, null, $headers) ?: ''; - } - $result = @json_decode($this->_last_response); - return $result ?: false; - } - - /** - * Fetch the last API response. - * - * @return string - */ - protected function _getLastResponse() - { - return $this->_last_response; - } -} diff --git a/common/scripts/cron.php b/common/scripts/cron.php index 563f71c70..19ea7b1c9 100644 --- a/common/scripts/cron.php +++ b/common/scripts/cron.php @@ -33,6 +33,7 @@ else } // Get queue configuration set by the administrator. +$display_errors = config('queue.display_errors') === false ? false : true; $timeout = (config('queue.interval') ?? 1) * 60; $process_count = config('queue.process_count') ?? 1; @@ -41,6 +42,14 @@ if (PHP_SAPI !== 'cli') { ignore_user_abort(true); set_time_limit(max(60, $timeout)); + if ($display_errors) + { + ini_set('display_errors', true); + } + if (Rhymix\Framework\Session::checkStart()) + { + Rhymix\Framework\Session::close(); + } } // Create multiple processes if configured. @@ -89,3 +98,9 @@ else { Rhymix\Framework\Queue::process($timeout); } + +// If called over the network, display a simple OK message to indicate success. +if (PHP_SAPI !== 'cli') +{ + echo "OK\n"; +} diff --git a/common/tpl/common_layout.html b/common/tpl/common_layout.html index 04a7e326d..b4d64176c 100644 --- a/common/tpl/common_layout.html +++ b/common/tpl/common_layout.html @@ -7,11 +7,12 @@ - -@foreach (Context::getMetaTag() as $val) - -@endforeach +@foreach (Context::getMetaTag() as $val) +@if ($val['is_before_title']) + +@endif +@endforeach
%s account and run crontab -e to paste the following content into your crontab. (DO NOT run it as root!)%s directory in the example should be replaced with a path where logs can be recorded.';
-$lang->msg_queue_instructions['crontab2'] = 'If you change the calling interval below, the crontab interval must be adjusted accordingly.';
+$lang->msg_queue_instructions['crontab1'] = 'Log into the server as the %s account and run crontab -e to paste the following content into your crontab. (DO NOT run it as root!)apache or www-data, try running sudo crontab -e -u %s from a different account.';
+$lang->msg_queue_instructions['crontab2'] = 'The %s directory in the example should be replaced with a path where logs can be recorded./etc/systemd/system/rhymix-queue.service';
$lang->msg_queue_instructions['systemd2'] = 'Put the following content in /etc/systemd/system/rhymix-queue.timer';
diff --git a/modules/admin/lang/ko.php b/modules/admin/lang/ko.php
index 7fd335612..3cb78e0e1 100644
--- a/modules/admin/lang/ko.php
+++ b/modules/admin/lang/ko.php
@@ -204,6 +204,9 @@ $lang->cache_truncate_method_empty = '캐시 내용만 삭제';
$lang->about_cache_truncate_method = '캐시 폴더를 삭제하는 방법이 더 빠르고 안정적입니다.crontab -e 명령을 실행한 후, 아래의 내용을 붙여넣으십시오. (root 권한으로 실행하지 마십시오.)%s 디렉토리는 로그를 기록할 수 있는 경로로 변경하여 사용하십시오.';
-$lang->msg_queue_instructions['crontab2'] = '스크립트 호출 간격을 변경할 경우, 설정에 맞추어 crontab 실행 간격도 조절하여야 합니다.';
+$lang->msg_queue_instructions['crontab1'] = '%s 계정으로 서버에 로그인하여 crontab -e 명령을 실행한 후, 아래의 내용을 붙여넣으십시오. (root 권한으로 실행하지 마십시오!)apache나 www-data처럼 로그인할 수 없는 계정이라면, 다른 계정에서 sudo crontab -e -u %s 명령을 실행해 볼 수 있습니다.';
+$lang->msg_queue_instructions['crontab2'] = '예제의 %s 디렉토리는 로그를 기록할 권한이 있는 경로로 변경하여 사용하십시오./etc/systemd/system/rhymix-queue.service 파일에 아래와 같은 내용을 넣습니다.';
$lang->msg_queue_instructions['systemd2'] = '/etc/systemd/system/rhymix-queue.timer 파일에 아래와 같은 내용을 넣습니다.';
diff --git a/modules/admin/tpl/config_advanced.html b/modules/admin/tpl/config_advanced.html
index 3378ea501..6373337fe 100644
--- a/modules/admin/tpl/config_advanced.html
+++ b/modules/admin/tpl/config_advanced.html
@@ -201,6 +201,13 @@
{$lang->about_cache_control_header}
+{$lang->about_outgoing_proxy}
+- {sprintf($lang->msg_queue_instructions['crontab1'], $user_info['name'] ?? 'PHP', $user_info['dir'] . 'logs')|noescape} + {sprintf($lang->msg_queue_instructions['crontab1'], $user_info['name'] ?? 'PHP', $user_info['name'] ?? 'PHP')|noescape}
-* * * * * php {\RX_BASEDIR}index.php common.cron >> {$user_info['dir']}logs{\DIRECTORY_SEPARATOR}queue.log 2>&1
+ * * * * * /usr/bin/php {\RX_BASEDIR}index.php common.cron >> {$user_info['dir']}logs{\DIRECTORY_SEPARATOR}queue.log 2>&1
- {$lang->msg_queue_instructions['crontab2']|noescape} + {sprintf($lang->msg_queue_instructions['crontab2'], $user_info['dir'] . 'logs')|noescape}
{$lang->msg_queue_instructions['systemd2']|noescape} @@ -167,6 +167,21 @@ systemctl enable rhymix-queue.timer
{$lang->cmd_queue_webcron_display_errors_help}
+