mirror of
https://github.com/gtbu/Typesetter-5.3-p8.git
synced 2024-11-24 15:19:12 +01:00
c61d9eb6e8
file_exists(): open_basedir restriction in effect. - php 8.2
2355 lines
58 KiB
PHP
2355 lines
58 KiB
PHP
<?php
|
|
|
|
namespace gp\tool{
|
|
|
|
defined('is_running') or die('Not an entry point...');
|
|
|
|
global $GP_ARRANGE, $gpOutConf;
|
|
|
|
$GP_ARRANGE = true;
|
|
$gpOutConf = [];
|
|
|
|
|
|
//named menus should just be shortcuts to the numbers in custom menu
|
|
// custom menu format: $top_level,$bottom_level,$expand_level
|
|
|
|
//custom menu: 0,0,0,0
|
|
$gpOutConf['FullMenu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'GetFullMenu',
|
|
'link' => 'all_links',
|
|
];
|
|
|
|
//custom menu: 0,0,1,1
|
|
$gpOutConf['ExpandMenu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'GetExpandMenu',
|
|
'link' => 'expanding_links',
|
|
];
|
|
|
|
//custom menu: 0,0,2,1
|
|
$gpOutConf['ExpandLastMenu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'GetExpandLastMenu',
|
|
'link' => 'expanding_bottom_links',
|
|
];
|
|
|
|
//custom menu: 0,1,0,0
|
|
$gpOutConf['Menu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'GetMenu',
|
|
'link' => 'top_level_links',
|
|
];
|
|
|
|
//custom menu: 1,0,0,0
|
|
$gpOutConf['SubMenu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'GetSubMenu',
|
|
'link' => 'subgroup_links',
|
|
];
|
|
|
|
//custom menu: 0,2,0,0
|
|
$gpOutConf['TopTwoMenu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'GetTopTwoMenu',
|
|
'link' => 'top_two_links',
|
|
];
|
|
|
|
//custom menu: does not translate, this pays no attention to grouping
|
|
$gpOutConf['BottomTwoMenu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'GetBottomTwoMenu',
|
|
'link' => 'bottom_two_links',
|
|
];
|
|
|
|
//custom menu: 1,2,0,0
|
|
$gpOutConf['MiddleSubMenu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'GetSecondSubMenu',
|
|
'link' => 'second_sub_links',
|
|
];
|
|
|
|
//custom menu: 2,3,0,0
|
|
$gpOutConf['BottomSubMenu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'GetThirdSubMenu',
|
|
'link' => 'third_sub_links',
|
|
];
|
|
|
|
//custom menu
|
|
$gpOutConf['CustomMenu'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'CustomMenu',
|
|
];
|
|
|
|
//breadcrumb nav
|
|
$gpOutConf['Breadcrumbs'] = [
|
|
'class' => '\\gp\\tool\\Output\\Menu',
|
|
'method' => 'BreadcrumbNav',
|
|
'link' => 'Breadcrumb Links',
|
|
];
|
|
//$gpOutConf['Breadcrumbs']['method'] = ['\\gp\\tool\\Output', 'BreadcrumbNav'];
|
|
//$gpOutConf['Breadcrumbs']['link'] = 'Breadcrumb Links';
|
|
|
|
|
|
$gpOutConf['Extra']['method'] = ['\\gp\\tool\\Output', 'GetExtra'];
|
|
|
|
//$gpOutConf['Text']['method'] = ['\\gp\\tool\\Output','GetText']; //use Area() and GetArea() instead
|
|
|
|
//$gpOutConf['Image']['method'] = ['\\gp\\tool\\Output','GetImage'];
|
|
|
|
/* The following methods should be used with \gp\tool\Output'::Fetch() */
|
|
$gpOutConf['Gadget']['method'] = ['\\gp\\tool\\Output', 'GetGadget'];
|
|
|
|
|
|
class Output{
|
|
|
|
public static $components = '';
|
|
public static $editlinks = '';
|
|
public static $template_included = false;
|
|
|
|
private static $out_started = false;
|
|
private static $gadget_cache = [];
|
|
|
|
public static $edit_area_id = '';
|
|
|
|
private static $catchable = [];
|
|
|
|
public static $lang_values = [];
|
|
public static $inline_vars = [];
|
|
public static $nested_edit = false;
|
|
|
|
private static $edit_index = 0;
|
|
|
|
private static $head_css = '';
|
|
private static $head_content = '';
|
|
private static $head_js = '';
|
|
|
|
|
|
/**
|
|
* Backwards compat for functions moved to \gp\tool\Output\Menu
|
|
*
|
|
*/
|
|
public static function __callStatic($name, $args){
|
|
|
|
if( method_exists('\\gp\\tool\\Output\\Menu', $name) ){
|
|
$menu = new \gp\tool\Output\Menu();
|
|
return call_user_func_array([$menu, $name], $args);
|
|
}
|
|
|
|
throw new \Exception('Call to undefined method gp\\tool\\Output::' . $name);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* Request Type Functions
|
|
* functions used in conjuction with $_REQUEST['gpreq']
|
|
*
|
|
*/
|
|
|
|
|
|
public static function Prep(){
|
|
global $page;
|
|
if( !isset($page->rewrite_urls) ){
|
|
return;
|
|
}
|
|
|
|
ini_set('arg_separator.output', '&');
|
|
foreach($page->rewrite_urls as $key => $value){
|
|
output_add_rewrite_var($key, $value);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Send only messages and the content buffer to the client
|
|
* @static
|
|
*/
|
|
public static function Flush(){
|
|
global $page;
|
|
self::StandardHeaders();
|
|
echo GetMessages();
|
|
echo $page->contentBuffer;
|
|
}
|
|
|
|
|
|
public static function Content(){
|
|
global $page;
|
|
self::StandardHeaders();
|
|
echo GetMessages();
|
|
$page->GetGpxContent();
|
|
}
|
|
|
|
|
|
public static function StandardHeaders(){
|
|
header('Content-Type: text/html; charset=utf-8');
|
|
Header('Vary: Accept,Accept-Encoding'); // for proxies
|
|
}
|
|
|
|
|
|
/**
|
|
* Send only the messages and content as a simple html document
|
|
* @static
|
|
*/
|
|
public static function BodyAsHTML(){
|
|
global $page;
|
|
|
|
self::$inline_vars['gp_bodyashtml'] = true;
|
|
|
|
self::TemplateSettings();
|
|
|
|
self::StandardHeaders();
|
|
|
|
echo '<!DOCTYPE html>';
|
|
echo '<html lang="' . $page->lang . '"><head><meta charset="UTF-8" />';
|
|
self::getHead();
|
|
echo '</head>';
|
|
|
|
echo '<body class="gpbody">';
|
|
echo GetMessages();
|
|
|
|
$page->GetGpxContent();
|
|
|
|
echo '</body>';
|
|
echo '</html>';
|
|
|
|
self::HeadContent();
|
|
}
|
|
|
|
|
|
public static function AdminHtml(){
|
|
global $page;
|
|
|
|
//\gp\tool\Output::$inline_vars['gp_bodyashtml'] = true;
|
|
|
|
self::StandardHeaders();
|
|
|
|
echo '<!DOCTYPE html>';
|
|
echo '<html class="admin_body" lang="' . $page->lang . '"><head><meta charset="UTF-8" />';
|
|
self::getHead();
|
|
echo '</head>';
|
|
|
|
echo '<body class="gpbody">';
|
|
echo GetMessages();
|
|
|
|
$page->GetGpxContent();
|
|
|
|
echo '</body>';
|
|
echo '</html>';
|
|
|
|
self::HeadContent();
|
|
}
|
|
|
|
|
|
/**
|
|
* Get default values from customizer if it exists
|
|
* return empty array otherwise
|
|
*
|
|
* Layout installer will pass a customizer file path
|
|
*
|
|
* @static
|
|
* @since 5.2
|
|
* @param string $used_in
|
|
* @param string $customizer_file
|
|
* @return array
|
|
*
|
|
*/
|
|
public static function GetCustomizerDefaults($used_in='', $customizer_file=''){
|
|
global $page;
|
|
|
|
if( empty($customizer_file) ){
|
|
$layout_dir = $page->theme_dir . '/' . $page->theme_color;
|
|
$customizer_file = $layout_dir . '/customizer.php';
|
|
}
|
|
|
|
$cust_path = stream_resolve_include_path($customizer_file);
|
|
if (!$cust_path || !is_readable($cust_path)) {
|
|
// msg('customizer file ' . htmlspecialchars($customizer_file) . ' does not exist'); // TODO remove
|
|
return [];
|
|
};
|
|
|
|
$customizer = \gp\tool\Files::Get($customizer_file, 'customizer');
|
|
// debug('$customizer = ' . pre($customizer));
|
|
$defaults = [];
|
|
|
|
foreach($customizer as $section => $section_data){
|
|
|
|
foreach($section_data['items'] as $item_name => $item_data){
|
|
if( !empty($used_in) &&
|
|
isset($item_data['control']['used_in']) &&
|
|
is_array($item_data['control']['used_in']) &&
|
|
!in_array($used_in, $item_data['control']['used_in'])
|
|
){
|
|
continue;
|
|
}
|
|
|
|
$defaults[$item_name]['value'] = $item_data['default_value'];
|
|
if( !empty($item_data['default_units']) ){
|
|
$defaults[$item_name]['units'] = $item_data['default_units'];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $defaults;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get javascript values from the layout
|
|
* if the layout has no stored js_vals, try to get customizer defaults
|
|
* otherwise return empty string
|
|
*
|
|
* @static
|
|
* @since 5.2
|
|
* @return string js expression like 'var layout_config = JSON;'
|
|
*
|
|
*/
|
|
public static function GetLayoutJsVars(){
|
|
global $page, $gpLayouts;
|
|
|
|
if( $page->gpLayout ){
|
|
$layout_info = $gpLayouts[$page->gpLayout];
|
|
if( isset($layout_info['js_vars']) ){
|
|
return $layout_info['js_vars'];
|
|
}
|
|
}
|
|
|
|
$js_vars = self::GetCustomizerDefaults('js');
|
|
return "\n" . 'var layout_config = ' . json_encode($js_vars) . ';' . "\n";
|
|
}
|
|
|
|
|
|
/**
|
|
* Get configuration array from the layout
|
|
* if the layout has no stored config, try to get customizer defaults
|
|
* otherwise return empty array
|
|
*
|
|
* @static
|
|
* @since 5.2
|
|
* @return array layout configuration
|
|
*
|
|
*/
|
|
public static function GetLayoutConfig(){
|
|
global $page, $gpLayouts;
|
|
|
|
if( $page->gpLayout ){
|
|
$layout_info = $gpLayouts[$page->gpLayout];
|
|
if( isset($layout_info['config']) ){
|
|
return $layout_info['config'];
|
|
}
|
|
}
|
|
|
|
return self::GetCustomizerDefaults('php');
|
|
}
|
|
|
|
|
|
/**
|
|
* Send all content according to the current layout
|
|
* @static
|
|
*
|
|
*/
|
|
public static function Template(){
|
|
global $page, $gpLayouts, $layout_config;
|
|
global $GP_ARRANGE, $GP_STYLES, $get_all_gadgets_called;
|
|
global $addon_current_id, $GP_MENU_LINKS, $GP_MENU_CLASS;
|
|
global $GP_MENU_CLASSES, $GP_MENU_ELEMENTS;
|
|
|
|
$get_all_gadgets_called = false;
|
|
self::$template_included = true;
|
|
|
|
if( isset($page->theme_addon_id) ){
|
|
$addon_current_id = $page->theme_addon_id;
|
|
}
|
|
self::TemplateSettings();
|
|
|
|
self::StandardHeaders();
|
|
|
|
if( !empty($page->preview_layout_config) ){
|
|
// only exists in Layout Editor preview mode
|
|
$layout_config = $page->preview_layout_config;
|
|
}elseif( empty($layout_config) ){
|
|
$layout_config = self::GetLayoutConfig();
|
|
}
|
|
// debug('$layout_config = ' . pre($layout_config));
|
|
|
|
$path = $page->theme_dir . '/template.php';
|
|
|
|
$return = IncludeScript(
|
|
$path,
|
|
'require',
|
|
[
|
|
'page', 'layout_config',
|
|
'GP_ARRANGE',
|
|
'GP_MENU_LINKS', 'GP_MENU_CLASS',
|
|
'GP_MENU_CLASSES', 'GP_MENU_ELEMENTS'
|
|
]
|
|
);
|
|
|
|
//return will be false if there's a fatal error with the template.php file
|
|
if( $return === false ){
|
|
self::BodyAsHtml();
|
|
}
|
|
\gp\tool\Plugins::ClearDataFolder();
|
|
|
|
self::HeadContent();
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the settings for the current theme if settings.php exists
|
|
* @static
|
|
*/
|
|
public static function TemplateSettings(){
|
|
global $page;
|
|
|
|
$path = $page->theme_dir . '/settings.php';
|
|
IncludeScript($path, 'require_if', ['page', 'GP_GETALLGADGETS']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a Header to the response
|
|
* The header will be discarded if it's an ajax request or similar
|
|
*
|
|
* @param string $header
|
|
* @param bool $replace
|
|
* @param int $code
|
|
* @return bool
|
|
*/
|
|
public static function AddHeader($header, $replace=true, $code=null){
|
|
if( !empty($_REQUEST['gpreq']) ){
|
|
return false;
|
|
}
|
|
if( !is_null($code) ){
|
|
\gp\tool::status_header($code, $header);
|
|
}else{
|
|
header($header, $replace);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* Content Area Functions
|
|
*
|
|
*/
|
|
|
|
public static function GetContainerID($name, $arg=false){
|
|
static $indices;
|
|
|
|
$name = str_replace(
|
|
['+', '/', '='],
|
|
['', '', ''],
|
|
base64_encode($name)
|
|
);
|
|
if( !isset($indices[$name]) ){
|
|
$indices[$name] = 0;
|
|
}else{
|
|
$indices[$name]++;
|
|
}
|
|
return $name . '_' . $indices[$name];
|
|
}
|
|
|
|
|
|
/**
|
|
* Fetch the output and return as a string
|
|
*
|
|
*/
|
|
public static function Fetch($default, $arg=''){
|
|
ob_start();
|
|
self::Get($default, $arg);
|
|
return ob_get_clean();
|
|
}
|
|
|
|
|
|
public static function Get($default='', $arg=''){
|
|
global $page, $gpLayouts, $gpOutConf;
|
|
|
|
$outSet = false;
|
|
$outKeys = false;
|
|
|
|
$layout_info =& $gpLayouts[$page->gpLayout];
|
|
|
|
//container id
|
|
$container_id = $default . ':' . substr($arg, 0, 10);
|
|
$container_id = self::GetContainerID($container_id);
|
|
|
|
if( isset($layout_info) && isset($layout_info['handlers']) ){
|
|
$handlers =& $layout_info['handlers'];
|
|
if( isset($handlers[$container_id]) ){
|
|
$outKeys = $handlers[$container_id];
|
|
$outSet = true;
|
|
}
|
|
}
|
|
|
|
//default values
|
|
if( !$outSet && isset($gpOutConf[$default]) ){
|
|
$outKeys =array();
|
|
$outKeys[] = trim($default . ':' . $arg, ':');
|
|
}
|
|
|
|
self::ForEachOutput($outKeys, $container_id);
|
|
}
|
|
|
|
|
|
public static function ForEachOutput($outKeys, $container_id){
|
|
|
|
if( !is_array($outKeys) || (count($outKeys) == 0) ){
|
|
$info = [];
|
|
$info['gpOutCmd'] = '';
|
|
self::CallOutput($info, $container_id);
|
|
return;
|
|
}
|
|
|
|
foreach($outKeys as $gpOutCmd){
|
|
$info = self::GetgpOutInfo($gpOutCmd);
|
|
if( $info === false ){
|
|
trigger_error('gpOutCmd <i>' . $gpOutCmd . '</i> not set');
|
|
continue;
|
|
}
|
|
$info['gpOutCmd'] = $gpOutCmd;
|
|
self::CallOutput($info, $container_id);
|
|
}
|
|
}
|
|
|
|
|
|
/* static */
|
|
public static function GetgpOutInfo($gpOutCmd){
|
|
global $gpOutConf, $config;
|
|
|
|
$key = $gpOutCmd = trim($gpOutCmd, ':');
|
|
$info = false;
|
|
$arg = '';
|
|
$pos = mb_strpos($key, ':');
|
|
|
|
if( $pos > 0 ){
|
|
$arg = mb_substr($key, $pos + 1);
|
|
$key = mb_substr($key, 0, $pos);
|
|
}
|
|
|
|
if( isset($gpOutConf[$key]) ){
|
|
$info = $gpOutConf[$key];
|
|
}elseif( isset($config['gadgets'][$key]) ){
|
|
$info = $config['gadgets'][$key];
|
|
$info['is_gadget'] = true;
|
|
}else{
|
|
return false;
|
|
}
|
|
|
|
$info['key'] = $key;
|
|
$info['arg'] = $arg;
|
|
$info['gpOutCmd'] = $gpOutCmd;
|
|
|
|
return $info;
|
|
}
|
|
|
|
|
|
|
|
public static function GpOutLabel($info){
|
|
global $langmessage;
|
|
|
|
$info += ['arg' => '']; // suppress warning with older themes TODO: check the cause
|
|
$label = $info['arg'];
|
|
if( empty($label) ){
|
|
$label = $info['gpOutCmd'];
|
|
}
|
|
|
|
if( isset($info['link']) && isset($langmessage[$info['link']]) ){
|
|
$label = $langmessage[$info['link']];
|
|
}
|
|
|
|
return str_replace([' ', '_', ':'], [' ', ' ', ': '], $label);
|
|
}
|
|
|
|
|
|
public static function CallOutput($info,$container_id){
|
|
global $GP_ARRANGE, $page, $langmessage, $GP_MENU_LINKS;
|
|
global $GP_MENU_CLASS, $GP_MENU_CLASSES, $gp_current_container;
|
|
|
|
$gp_current_container = $container_id;
|
|
self::$out_started = true;
|
|
self::$edit_area_id = '';
|
|
|
|
if( isset($info['disabled']) ){
|
|
return;
|
|
}
|
|
|
|
//gpOutCmd identifies the output function used, there can only be one
|
|
if( !isset($info['gpOutCmd']) ){
|
|
trigger_error('gpOutCmd not set for $info in CallOutput()');
|
|
return;
|
|
}
|
|
|
|
//generate a class based on the area $info
|
|
if( isset($info['html']) ){
|
|
$class = $info['key'];
|
|
$class = preg_replace('#\[.*\]#', '', $class);
|
|
}else{
|
|
$class = $info['gpOutCmd'];
|
|
}
|
|
|
|
//add gpMenu class to all menu areas for better styling
|
|
$add_menu_class = '';
|
|
if( isset($info['class']) && $info['class'] == '\gp\tool\Output\Menu' ){
|
|
$add_menu_class = 'gpMenu ';
|
|
}
|
|
$class = $add_menu_class . 'gpArea_' . str_replace([':', ','], ['_', ''], trim($class, ':'));
|
|
$param = $container_id . '|' . $info['gpOutCmd'];
|
|
$permission = self::ShowEditLink('Admin_Theme_Content');
|
|
|
|
|
|
ob_start();
|
|
|
|
//for theme content arrangement
|
|
if( $GP_ARRANGE && $permission && isset($GLOBALS['GP_ARRANGE_CONTENT']) ){
|
|
$empty_container = empty($info['gpOutCmd']); //empty containers can't be removed and don't have labels
|
|
$class .= ' gp_output_area';
|
|
|
|
echo '<div class="gp_inner_links nodisplay"><div>';
|
|
echo \gp\tool::Link(
|
|
'Admin_Theme_Content/Edit/' . $page->gpLayout,
|
|
$param,
|
|
'cmd=DragArea&dragging=' . urlencode($param) . '&to=%s',
|
|
['data-cmd' => 'creq', 'class' => 'dragdroplink nodisplay']
|
|
); //drag-drop link
|
|
|
|
echo '<div class="output_area_label">';
|
|
if( $empty_container ){
|
|
echo $langmessage['Empty Container'];
|
|
}else{
|
|
echo self::GpOutLabel($info);
|
|
}
|
|
echo '</div>';
|
|
|
|
echo '<div class="output_area_link">';
|
|
echo ' ' . \gp\tool::Link(
|
|
'Admin_Theme_Content/Edit/' . $page->gpLayout,
|
|
'<i class="fa fa-plus"></i> ' . $langmessage['insert'],
|
|
'cmd=SelectContent¶m=' . $param,
|
|
['data-cmd' => 'gpabox']
|
|
);
|
|
if( !$empty_container ){
|
|
echo ' ' . \gp\tool::Link(
|
|
'Admin_Theme_Content/Edit/' . $page->gpLayout,
|
|
'<i class="fa fa-times"></i> ' . $langmessage['remove'],
|
|
'cmd=RemoveArea¶m=' . $param,
|
|
['data-cmd' => 'creq']
|
|
);
|
|
}
|
|
echo '</div>';
|
|
|
|
echo '</div></div>';
|
|
|
|
}
|
|
|
|
//editable links only .. other editable_areas are handled by their output functions
|
|
if( $permission ){
|
|
if( isset($info['link']) ){
|
|
$label = $langmessage[$info['link']];
|
|
|
|
$edit_link = self::EditAreaLink(
|
|
$edit_index,
|
|
'Admin_Theme_Content/Edit/' . urlencode($page->gpLayout),
|
|
$langmessage['edit'],
|
|
'cmd=LayoutMenu&handle=' . $param,
|
|
['data-cmd' => 'gpabox', 'title' => $label ]
|
|
);
|
|
echo '<span class="nodisplay" id="ExtraEditLnks' . $edit_index . '">';
|
|
echo $edit_link;
|
|
echo \gp\tool::Link(
|
|
'Admin/Menu',
|
|
$langmessage['file_manager'],
|
|
'',
|
|
['class' => 'nodisplay']
|
|
);
|
|
//call to current also not needed, there will only be 1 entry);
|
|
echo '</span>';
|
|
|
|
self::$edit_area_id = 'ExtraEditArea'.$edit_index;
|
|
|
|
}elseif( isset($info['key']) && ($info['key'] == 'CustomMenu') ){
|
|
|
|
$edit_link = self::EditAreaLink(
|
|
$edit_index,
|
|
'Admin_Theme_Content/Edit/' . urlencode($page->gpLayout),
|
|
$langmessage['edit'],
|
|
'cmd=LayoutMenu&handle=' . $param,
|
|
['data-cmd' => 'gpabox', 'title' => $langmessage['Links']]
|
|
);
|
|
|
|
echo '<span class="nodisplay" id="ExtraEditLnks' . $edit_index . '">';
|
|
|
|
echo $edit_link;
|
|
|
|
echo \gp\tool::Link(
|
|
'Admin/Menu',
|
|
$langmessage['file_manager'],
|
|
'',
|
|
['class' => 'nodisplay']
|
|
);
|
|
|
|
echo '</span>';
|
|
|
|
self::$edit_area_id = 'ExtraEditArea' . $edit_index;
|
|
}
|
|
}
|
|
|
|
self::$editlinks .= ob_get_clean();
|
|
|
|
echo '<div class="' . $class . ' GPAREA">';
|
|
self::ExecArea($info);
|
|
echo '</div>';
|
|
|
|
$GP_ARRANGE = true;
|
|
$gp_current_container = false;
|
|
}
|
|
|
|
|
|
public static function ExecArea($info){
|
|
//retreive from gadget cache if set
|
|
if( isset($info['gpOutCmd']) ){
|
|
$gadget = $info['gpOutCmd'];
|
|
if( substr($gadget, 0, 7) == 'Gadget:' ){
|
|
$gadget = substr($gadget, 7);
|
|
}
|
|
if( isset(self::$gadget_cache[$gadget]) ){
|
|
echo self::$gadget_cache[$gadget];
|
|
return;
|
|
}
|
|
}
|
|
|
|
$info += ['arg' => ''];
|
|
$args = [$info['arg'], $info];
|
|
|
|
$info = \gp\tool\Plugins::Filter('ExecArea', [$info, $args]);
|
|
if( !$info ){
|
|
return;
|
|
}
|
|
|
|
self::ExecInfo($info, $args);
|
|
}
|
|
|
|
|
|
/**
|
|
* Execute a set of directives for theme areas, hooks and special pages
|
|
*
|
|
*/
|
|
public static function ExecInfo($info, $args=[]){
|
|
global $addonFolderName, $installed_addon, $page;
|
|
|
|
$args += ['page' => $page];
|
|
|
|
//addonDir is deprecated as of 2.0b3
|
|
$addon = false;
|
|
if( isset($info['addonDir']) ){
|
|
$addon = $info['addonDir'];
|
|
}elseif( isset($info['addon']) ){
|
|
$addon = $info['addon'];
|
|
}
|
|
|
|
if( $addon !== false ){
|
|
if( gp_safe_mode ){
|
|
return $args;
|
|
}
|
|
\gp\tool\Plugins::SetDataFolder($addon);
|
|
}
|
|
|
|
//if addon was just installed
|
|
if( $installed_addon && $installed_addon === $addonFolderName){
|
|
\gp\tool\Plugins::ClearDataFolder();
|
|
return $args;
|
|
}
|
|
|
|
// check for fatal errors
|
|
if( self::FatalNotice('exec', $info) ){
|
|
return $args;
|
|
}
|
|
|
|
try{
|
|
$args = self::_ExecInfo($info, $args);
|
|
}catch(\Throwable $e){
|
|
\showError(E_ERROR,
|
|
'ExecInfo() Fatal Error: ' . $e->getMessage(),
|
|
$e->GetFile(),
|
|
$e->GetLine(),
|
|
[],
|
|
$e->getTrace()
|
|
);
|
|
}
|
|
|
|
if( $addon !== false ){
|
|
\gp\tool\Plugins::ClearDataFolder();
|
|
}
|
|
|
|
self::PopCatchable();
|
|
|
|
return $args;
|
|
}
|
|
|
|
|
|
public static function _ExecInfo($info, $args=[]){
|
|
global $dataDir, $gp_overwrite_scripts;
|
|
|
|
// get data
|
|
if( !empty($info['data']) ){
|
|
IncludeScript($dataDir . $info['data'], 'include_if', ['page', 'dataDir', 'langmessage']);
|
|
}
|
|
|
|
// get script
|
|
$has_script = false;
|
|
if( !empty($info['script']) ){
|
|
|
|
if( is_array($gp_overwrite_scripts) && isset($gp_overwrite_scripts[$info['script']]) ){
|
|
$full_path = $gp_overwrite_scripts[$info['script']];
|
|
}else{
|
|
$full_path = $dataDir . $info['script'];
|
|
}
|
|
|
|
if( !file_exists($full_path) ){
|
|
self::ExecError(\CMS_NAME . ' Error: Addon hook script doesn\'t exist.', $info, 'script');
|
|
return $args;
|
|
}
|
|
|
|
if( IncludeScript($full_path, 'include_once', ['page', 'dataDir', 'langmessage']) ){
|
|
$has_script = true;
|
|
}
|
|
}
|
|
|
|
//class & method execution
|
|
if( !empty($info['class_admin']) && \gp\tool::LoggedIn() ){
|
|
return self::ExecClass($has_script, $info['class_admin'], $info, $args);
|
|
}elseif( !empty($info['class']) ){
|
|
return self::ExecClass($has_script, $info['class'], $info, $args);
|
|
}
|
|
|
|
//method execution
|
|
if( !empty($info['method']) ){
|
|
return self::ExecMethod($has_script, $info, $args);
|
|
}
|
|
|
|
return $args;
|
|
}
|
|
|
|
|
|
/**
|
|
* Execute hooks that have a ['class'] defined
|
|
*
|
|
*/
|
|
private static function ExecClass($has_script, $exec_class, $info, $args){
|
|
|
|
if( !class_exists($exec_class) ){
|
|
self::ExecError(\CMS_NAME . ' Error: Addon class doesn\'t exist.', $info, 'class');
|
|
return $args;
|
|
}
|
|
|
|
$object = new $exec_class($args);
|
|
|
|
if( !empty($info['method']) ){
|
|
if( method_exists($object, $info['method']) ){
|
|
$args[0] = call_user_func_array([$object, $info['method']], array_values($args));
|
|
}elseif( $has_script ){
|
|
self::ExecError(\CMS_NAME . ' Error: Addon hook method doesn\'t exist (1).', $info, 'method');
|
|
}
|
|
}
|
|
return $args;
|
|
}
|
|
|
|
|
|
/**
|
|
* Execute hooks that have a ['method'] defined
|
|
*
|
|
*/
|
|
private static function ExecMethod($has_script, $info, $args){
|
|
|
|
$callback = $info['method'];
|
|
|
|
//object callbacks since 3.0
|
|
if( is_string($callback) && strpos($callback, '->') !== false ){
|
|
$has_script = true;
|
|
list($object, $method) = explode('->', $callback);
|
|
if( isset($GLOBALS[$object]) &&
|
|
is_object($GLOBALS[$object]) &&
|
|
method_exists($GLOBALS[$object], $method)
|
|
){
|
|
$callback = [$GLOBALS[$object], $method];
|
|
}
|
|
}
|
|
|
|
if( is_callable($callback) ){
|
|
$args[0] = call_user_func_array($callback, array_values($args));
|
|
}elseif( $has_script ){
|
|
self::ExecError(\CMS_NAME.' Error: Addon hook method doesn\'t exist (2).', $info, 'method');
|
|
}
|
|
|
|
return $args;
|
|
}
|
|
|
|
|
|
/**
|
|
* Trigger an error
|
|
*
|
|
*/
|
|
public static function ExecError($msg, $exec_info, $error_info){
|
|
global $config, $addonFolderName;
|
|
|
|
// append addon name
|
|
if( !empty($addonFolderName) && isset($config['addons'][$addonFolderName]) ){
|
|
$msg .= ' Addon: ' . $config['addons'][$addonFolderName]['name'] . '. ';
|
|
}
|
|
|
|
// which piece of $exec_info is the problem
|
|
if( !isset($exec_info[$error_info]) ){
|
|
$msg .= $error_info;
|
|
}elseif( is_array($exec_info[$error_info]) ){
|
|
$msg .= $error_info . ': ' . implode('::', $exec_info[$error_info]);
|
|
}else{
|
|
$msg .= $error_info . ': ' . $exec_info[$error_info];
|
|
}
|
|
|
|
trigger_error($msg);
|
|
}
|
|
|
|
|
|
/**
|
|
* Check for fatal errors corresponing to $hash
|
|
* Notify administrators of disabled components
|
|
*
|
|
*/
|
|
public static function FatalNotice($type, $info){
|
|
global $dataDir, $page;
|
|
static $notified = false;
|
|
|
|
$info = (array)$info;
|
|
$info['catchable_type'] = $type;
|
|
|
|
$hash_dir = $dataDir . '/data/_site/fatal_' . $type . '_' . \gp\tool::ArrayHash($info);
|
|
$hash_request = $hash_dir . '/' . \gp\tool::ArrayHash($_REQUEST);
|
|
|
|
self::$catchable[$hash_request] = $info;
|
|
|
|
if( !self::FatalLimit($hash_dir) ){
|
|
return false;
|
|
}
|
|
|
|
if( !$notified ){
|
|
error_log( 'Warning: A component of this page has been disabled because it caused fatal errors' );
|
|
$notified = true;
|
|
}
|
|
|
|
self::PopCatchable();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return true if the limit of fatal errors has been reached
|
|
*
|
|
*/
|
|
public static function FatalLimit($hash_dir){
|
|
|
|
//no folder = no fatal error
|
|
if( !file_exists($hash_dir) ){
|
|
return false;
|
|
}
|
|
|
|
// if the error didn't occur for the exact request and it hasn't happend a lot, allow the code to keep working
|
|
$fatal_hashes = scandir($hash_dir);
|
|
if( $fatal_hashes !== false && count($fatal_hashes) < (gp_allowed_fatal_errors + 3) ){
|
|
// add 3 for ".", ".." and "index.html" entries
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
public static function PopCatchable(){
|
|
array_pop(self::$catchable);
|
|
}
|
|
|
|
|
|
/**
|
|
* Determine if an inline edit link should be shown for the current user
|
|
*
|
|
* @param string $permission
|
|
* @return bool
|
|
*/
|
|
public static function ShowEditLink($permission=null){
|
|
|
|
if( !is_null($permission) ){
|
|
return !self::$nested_edit && \gp\tool::LoggedIn() && \gp\admin\Tools::HasPermission($permission);
|
|
}
|
|
return !self::$nested_edit && \gp\tool::LoggedIn();
|
|
}
|
|
|
|
|
|
/**
|
|
* @param int $index
|
|
* @param string $href
|
|
* @param string $label
|
|
* @param string $query
|
|
* @param string|array $attr
|
|
*
|
|
*/
|
|
public static function EditAreaLink(&$index, $href, $label, $query='', $attr=''){
|
|
self::$edit_index++;
|
|
$index = self::$edit_index; //since &$index is passed by reference
|
|
|
|
if( is_array($attr) ){
|
|
$attr += [
|
|
'class' => 'ExtraEditLink nodisplay',
|
|
'id' => 'ExtraEditLink' . $index,
|
|
'data-gp-area-id' => $index,
|
|
];
|
|
}else{
|
|
$attr .= ' class="ExtraEditLink nodisplay" ' .
|
|
'id="ExtraEditLink' . $index . '" ' .
|
|
'data-gp-area-id="' . $index . '"';
|
|
}
|
|
return \gp\tool::Link($href, $label, $query, $attr);
|
|
}
|
|
|
|
|
|
/**
|
|
* Unless the gadget area is customized by the user, this function will output all active gadgets
|
|
* If the area has been reorganized, it will output the customized areas
|
|
* This function is not called from \gp\tool\Output::Get('GetAllGadgets')
|
|
* so that each individual gadget area can be used as a drag area
|
|
*
|
|
*/
|
|
public static function GetAllGadgets(){
|
|
global $config, $page, $gpLayouts, $get_all_gadgets_called;
|
|
$get_all_gadgets_called = true;
|
|
|
|
//if we have handler info
|
|
if( isset($gpLayouts[$page->gpLayout]['handlers']['GetAllGadgets']) ){
|
|
self::ForEachOutput($gpLayouts[$page->gpLayout]['handlers']['GetAllGadgets'], 'GetAllGadgets');
|
|
return;
|
|
}
|
|
|
|
//show all gadgets if no changes have been made
|
|
if( !empty($config['gadgets']) ){
|
|
$count = 0;
|
|
foreach($config['gadgets'] as $gadget => $info){
|
|
if( isset($info['addon']) ){
|
|
$info['gpOutCmd'] = $info['key'] = $gadget;
|
|
self::CallOutput($info, 'GetAllGadgets');
|
|
$count++;
|
|
}
|
|
}
|
|
if( $count ){
|
|
return;
|
|
}
|
|
}
|
|
|
|
//Show the area as editable if there isn't anything to show
|
|
$info = [];
|
|
$info['gpOutCmd'] = '';
|
|
self::CallOutput($info, 'GetAllGadgets');
|
|
}
|
|
|
|
|
|
/**
|
|
* Simply determine if a Gadget exists
|
|
* allows us to check whether a plugin gadget exists before loading it in template.php
|
|
* @since 5.2-rc
|
|
* @param string Gadget id
|
|
* @return boolean
|
|
*/
|
|
public static function GadgetExists($id){
|
|
global $config;
|
|
return isset($config['gadgets'][$id]);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get a Single Gadget
|
|
* This method should be called using \gp\tool\Output::Fetch('Gadget',$gadget_name)
|
|
*
|
|
*/
|
|
public static function GetGadget($id){
|
|
global $config;
|
|
|
|
if( !isset($config['gadgets'][$id]) ){
|
|
return;
|
|
}
|
|
|
|
self::ExecArea($config['gadgets'][$id]);
|
|
}
|
|
|
|
|
|
/**
|
|
* Prepare the gadget content before getting template.php
|
|
* so that gadget functions can add css and js to the head
|
|
* @return null
|
|
*/
|
|
public static function PrepGadgetContent(){
|
|
global $page;
|
|
|
|
//not needed for admin pages
|
|
if( $page->pagetype == 'admin_display' ){
|
|
return;
|
|
}
|
|
|
|
$gadget_info = self::WhichGadgets($page->gpLayout);
|
|
|
|
foreach($gadget_info as $gpOutCmd => $info){
|
|
if( !isset(self::$gadget_cache[$gpOutCmd]) ){
|
|
ob_start();
|
|
self::ExecArea($info);
|
|
self::$gadget_cache[$gpOutCmd] = ob_get_clean();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Return information about the gadgets being used in the current layout
|
|
* @return array
|
|
*/
|
|
public static function WhichGadgets($layout){
|
|
global $config, $gpLayouts;
|
|
|
|
$gadget_info = $temp_info = [];
|
|
if( !isset($config['gadgets']) ){
|
|
return $gadget_info;
|
|
}
|
|
|
|
$layout_info = & $gpLayouts[$layout];
|
|
|
|
$GetAllGadgets = true;
|
|
if( isset($layout_info['all_gadgets']) && !$layout_info['all_gadgets'] ){
|
|
$GetAllGadgets = false;
|
|
}
|
|
|
|
if( isset($layout_info['handlers']) ){
|
|
foreach($layout_info['handlers'] as $handler => $out_cmds){
|
|
//don't prep even if GetAllGadgets is set in the layout's config
|
|
if( $handler == 'GetAllGadgets' && !$GetAllGadgets ){
|
|
continue;
|
|
}
|
|
foreach($out_cmds as $gpOutCmd){
|
|
$temp_info[$gpOutCmd] = self::GetgpOutInfo($gpOutCmd);
|
|
}
|
|
}
|
|
}
|
|
|
|
//add all gadgets if $GetAllGadgets is true and the GetAllGadgets handler isn't overwritten
|
|
if( $GetAllGadgets && !isset($layout_info['handlers']['GetAllGadgets']) ){
|
|
foreach($config['gadgets'] as $gadget => $temp){
|
|
if( isset($temp['addon']) ){
|
|
$temp_info[$gadget] = self::GetgpOutInfo($gadget);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach($temp_info as $gpOutCmd => $info){
|
|
if( isset($info['is_gadget']) &&
|
|
$info['is_gadget'] &&
|
|
!isset($info['disabled'])
|
|
){
|
|
$gadget_info[$gpOutCmd] = $info;
|
|
}
|
|
}
|
|
|
|
return $gadget_info;
|
|
}
|
|
|
|
|
|
public static function GetExtra($name='Side_Menu', $info=[]){
|
|
echo \gp\tool\Output\Extra::GetExtra($name);
|
|
}
|
|
|
|
|
|
public static function GetImage($src, $attributes=[]){
|
|
global $page, $dataDir, $langmessage, $gpLayouts;
|
|
|
|
//$width,$height,$attributes = ''
|
|
$attributes = (array)$attributes;
|
|
$attributes += ['class' => ''];
|
|
$attributes['class'] .= 'GPAREA filetype-image';
|
|
unset($attributes['id']);
|
|
|
|
//default image information
|
|
$img_rel = dirname($page->theme_rel) . '/' . ltrim($src, '/');
|
|
|
|
//container id
|
|
$container_id = 'Image:' . $src;
|
|
$container_id = self::GetContainerID($container_id);
|
|
|
|
//select custom image
|
|
if( isset($gpLayouts[$page->gpLayout]) &&
|
|
isset($gpLayouts[$page->gpLayout]['images']) &&
|
|
isset($gpLayouts[$page->gpLayout]['images'][$container_id]) &&
|
|
is_array($gpLayouts[$page->gpLayout]['images'][$container_id])
|
|
){
|
|
//shuffle($gpLayouts[$page->gpLayout]['images'][$container_id]);
|
|
//Does not make sense ? There will always be only 1 entry in
|
|
//for this container as it is per img element
|
|
//call to current also not needed, there will only be 1 entry
|
|
$image = $gpLayouts[$page->gpLayout]['images'][$container_id][0];
|
|
|
|
$img_full = $dataDir.$image['img_rel'];
|
|
if( file_exists($img_full) ){
|
|
$img_rel = $image['img_rel'];
|
|
$attributes['width'] = $image['width'];
|
|
$attributes['height'] = $image['height'];
|
|
}
|
|
}
|
|
|
|
//attributes
|
|
if( !isset($attributes['alt']) ){
|
|
$attributes['alt'] = '';
|
|
}
|
|
|
|
//edit options
|
|
$editable = self::ShowEditLink('Admin_Theme_Content');
|
|
if( $editable ){
|
|
$edit_link = self::EditAreaLink(
|
|
$edit_index,
|
|
'Admin_Theme_Content/Image/' . $page->gpLayout,
|
|
$langmessage['edit'],
|
|
'file=' . rawurlencode($img_rel) . '&container=' . $container_id . '&time=' . time(),
|
|
['title' => 'Edit Image', 'data-cmd' => 'inline_edit_generic' ]
|
|
);
|
|
self::$editlinks .= '<span class="nodisplay" id="ExtraEditLnks' .
|
|
$edit_index . '">' .
|
|
$edit_link .
|
|
'</span>';
|
|
$attributes['class'] .= ' editable_area';
|
|
$attributes['id'] = 'ExtraEditArea' . $edit_index;
|
|
}
|
|
|
|
//remove class if empty, commented because class will never be empty anymore because of filetype-image
|
|
// $attributes['class'] = trim($attributes['class']);
|
|
// if( empty($attributes['class']) ){
|
|
// unset($attributes['class']);
|
|
//}
|
|
|
|
//convert attributes to string
|
|
$str = '';
|
|
foreach($attributes as $key => $value){
|
|
$str .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8', false) . '"';
|
|
}
|
|
echo '<img src="' . \gp\tool::GetDir($img_rel, true) . '"' . $str . '/>';
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* Output Additional Areas
|
|
*
|
|
*/
|
|
|
|
/* draggable html and editable text */
|
|
public static function Area($name,$html){
|
|
global $gpOutConf;
|
|
if( self::$out_started ){
|
|
trigger_error('\gp\tool\Output::Area() must be called before all other output functions');
|
|
return;
|
|
}
|
|
$name = '[text]' . $name;
|
|
$gpOutConf[$name] = [];
|
|
$gpOutConf[$name]['method'] = ['\\gp\\tool\\Output', 'GetAreaOut'];
|
|
$gpOutConf[$name]['html'] = $html;
|
|
}
|
|
|
|
|
|
public static function GetArea($name, $text){
|
|
$name = '[text]' . $name;
|
|
self::Get($name, $text);
|
|
}
|
|
|
|
|
|
public static function GetAreaOut($text,$info){
|
|
global $config, $langmessage, $page;
|
|
|
|
$html =& $info['html'];
|
|
|
|
$wrap = self::ShowEditLink('Admin_Theme_Content');
|
|
if( $wrap ){
|
|
self::$editlinks .= self::EditAreaLink(
|
|
$edit_index,
|
|
'Admin_Theme_Content/Text',
|
|
$langmessage['edit'],
|
|
'cmd=EditText&key=' . urlencode(is_null($text) ? "" : urlencode($text)) . '&return=' . urlencode(is_null($page->title) ? "" : urlencode($page->title)),
|
|
['title' => htmlspecialchars($text), 'data-cmd' => 'gpabox']
|
|
);
|
|
echo '<div class="editable_area inner_size" id="ExtraEditArea' . $edit_index . '">';
|
|
// class="edit_area" added by javascript
|
|
}
|
|
|
|
if( isset($config['customlang'][$text]) ){
|
|
$text = $config['customlang'][$text];
|
|
|
|
}elseif( isset($langmessage[$text]) ){
|
|
$text = $langmessage[$text];
|
|
}
|
|
|
|
echo str_replace('%s', $text, $html); //in case there's more than one %s
|
|
|
|
if( $wrap ){
|
|
echo '</div>';
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get additional CSS classes that can be added to the
|
|
* html or body elements' class atrribute
|
|
* e.g. to display an larger header only on the homepage
|
|
* Use in template.php: <html class="<?php gpOutput::GetPageInfoClasses(); ?>">
|
|
* @since 5.2-rc
|
|
* @param boolean $echo_classes (defaults to true), output the class names as space-separated string
|
|
* @return array of css class names that apply
|
|
*
|
|
*/
|
|
public static function GetPageInfoClasses($echo_classes=true){
|
|
global $page;
|
|
|
|
$classes = [];
|
|
|
|
if( self::is_front_page() ){
|
|
$classes[] = 'is-homepage';
|
|
}
|
|
|
|
if( $page->pagetype == 'special_display' ){
|
|
$classes[] = 'is-special-page';
|
|
}
|
|
|
|
switch( $page->gp_index ){
|
|
case 'special_contact':
|
|
$classes[] = 'is-contactform-page';
|
|
break;
|
|
|
|
case 'special_galleries':
|
|
$classes[] = 'is-galleries-page';
|
|
break;
|
|
|
|
case 'special_gpsearch':
|
|
$classes[] = 'is-search-page';
|
|
break;
|
|
|
|
case 'special_missing':
|
|
$classes[] = 'is-missing-page';
|
|
break;
|
|
|
|
case 'special_blog':
|
|
$classes[] = 'is-blog-page';
|
|
if( isset($_GET['id']) ){
|
|
$classes[] = 'is-single-post-page';
|
|
}
|
|
break;
|
|
|
|
case 'special_blog_categories':
|
|
$classes[] = 'is-blog-page';
|
|
$classes[] = 'is-blog-categories-page';
|
|
if( isset($_GET['cat']) ){
|
|
$classes[] = 'is-single-category-page';
|
|
}
|
|
break;
|
|
}
|
|
|
|
if( $echo_classes && !empty($classes) ){
|
|
echo ' ' . implode(' ', $classes) . ' ';
|
|
}
|
|
|
|
return $classes;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* editable text, not draggable
|
|
*
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* similar to ReturnText() but links to script for editing all addon texts
|
|
* the $html parameter should primarily be used when the text is to be placed
|
|
* inside of a link or other element that cannot have a link and/or span as a child node
|
|
*/
|
|
public static function GetAddonText($key, $html='%s', $wrapper_class=''){
|
|
global $addonFolderName;
|
|
|
|
if( !$addonFolderName ){
|
|
return self::ReturnText($key, $html, $wrapper_class);
|
|
}
|
|
|
|
$query = 'cmd=AddonTextForm&addon=' . urlencode($addonFolderName) . '&key=' . urlencode($key);
|
|
return self::ReturnTextWorker($key, $html, $query, $wrapper_class);
|
|
}
|
|
|
|
|
|
public static function ReturnText($key,$html='%s', $wrapper_class=''){
|
|
$query = 'cmd=EditText&key='.urlencode($key);
|
|
return self::ReturnTextWorker($key, $html, $query, $wrapper_class);
|
|
}
|
|
|
|
|
|
public static function ReturnTextWorker($key, $html, $query, $wrapper_class=''){
|
|
global $langmessage;
|
|
|
|
$text = self::SelectText($key);
|
|
$result = str_replace('%s', $text, $html); //in case there's more than one %s
|
|
|
|
$editable = self::ShowEditLink('Admin_Theme_Content');
|
|
if( $editable ){
|
|
|
|
$title = htmlspecialchars(strip_tags($key));
|
|
if( strlen($title) > 20 ){
|
|
$title = substr($title, 0, 20) . '...'; //javscript may shorten it as well
|
|
}
|
|
|
|
self::$editlinks .= self::EditAreaLink(
|
|
$edit_index,
|
|
'Admin_Theme_Content/Text',
|
|
$langmessage['edit'],
|
|
$query,
|
|
['title' => $title, 'data-cmd' => 'gpabox']
|
|
);
|
|
return '<span class="editable_area ' . $wrapper_class .'" '
|
|
. 'id="ExtraEditArea' . $edit_index . '">' . $result . '</span>';
|
|
}
|
|
|
|
if( $wrapper_class ){
|
|
return '<span class="' . $wrapper_class . '">' . $result . '</span>';
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the user translated string if it exists or
|
|
* $key (the untranslated string) if a translation doesn't exist
|
|
*
|
|
*/
|
|
public static function SelectText($key){
|
|
global $config,$langmessage;
|
|
|
|
$text = $key;
|
|
if( isset($config['customlang'][$key]) ){
|
|
$text = $config['customlang'][$key];
|
|
|
|
}elseif( isset($langmessage[$key]) ){
|
|
$text = $langmessage[$key];
|
|
}
|
|
return $text;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* Generate and output the <head> portion of the html document
|
|
*
|
|
*/
|
|
|
|
public static function GetHead(){
|
|
\gp\tool\Plugins::Action('GetHead');
|
|
self::PrepGadgetContent();
|
|
echo '<!-- get_head_placeholder ' . \gp_random . ' -->';
|
|
}
|
|
|
|
|
|
public static function HeadContent(){
|
|
global $config, $page, $wbMessageBuffer;
|
|
|
|
//before ob_start() so plugins can get buffer content
|
|
\gp\tool\Plugins::Action('HeadContent');
|
|
|
|
|
|
if( \gp\tool::LoggedIn() ){
|
|
\gp\tool::AddColorBox();
|
|
}
|
|
|
|
//always include javascript when there are messages
|
|
if( $page->admin_js || !empty($page->jQueryCode) || !empty($wbMessageBuffer) || isset($_COOKIE['cookie_cmd']) ){
|
|
\gp\tool::LoadComponents('gp-main');
|
|
}
|
|
//defaults
|
|
\gp\tool::LoadComponents('jquery,gp-additional');
|
|
|
|
//get css and js info
|
|
$scripts = \gp\tool\Output\Combine::ScriptInfo( self::$components );
|
|
|
|
ob_start();
|
|
self::GetHead_TKD();
|
|
self::$head_content = ob_get_clean();
|
|
|
|
ob_start();
|
|
self::GetHead_CSS($scripts['css']); //css before js so it's available to scripts
|
|
self::$head_css = ob_get_clean();
|
|
|
|
//javascript
|
|
ob_start();
|
|
self::GetHead_Lang();
|
|
self::GetHead_JS($scripts['js']);
|
|
self::GetHead_InlineJS();
|
|
self::$head_js = ob_get_clean();
|
|
|
|
//gadget info
|
|
if( isset($config['addons']) ){
|
|
foreach($config['addons'] as $addon_info){
|
|
if( !empty($addon_info['html_head']) ){
|
|
self::MoveScript($addon_info['html_head']);
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !empty($page->head) ){
|
|
self::MoveScript($page->head);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Move <script>..</script> to self::$head_js
|
|
*
|
|
*/
|
|
public static function MoveScript($string){
|
|
|
|
//conditional comments with script tags
|
|
$patt = '#' . preg_quote('<!--[if', '#') . '.*?' . preg_quote('<![endif]-->', '#') . '#s';
|
|
if( preg_match_all($patt,$string, $matches) ){
|
|
foreach($matches[0] as $match){
|
|
if( strpos($match,'<script') !== false ){
|
|
$string = str_replace($match, '', $string);
|
|
self::$head_js .= "\n" . $match;
|
|
}
|
|
}
|
|
}
|
|
|
|
//script tags
|
|
if( preg_match_all('#<script.*?</script>#i',$string,$matches) ){
|
|
foreach($matches[0] as $match){
|
|
$string = str_replace($match, '', $string);
|
|
self::$head_js .= "\n" . $match;
|
|
}
|
|
}
|
|
|
|
//add the rest to the head_content
|
|
self::$head_content .= "\n" . $string;
|
|
}
|
|
|
|
|
|
/**
|
|
* Output the title, keywords, description and other meta for the current html document
|
|
* @static
|
|
*/
|
|
public static function GetHead_TKD(){
|
|
global $config, $page, $gpLayouts;
|
|
|
|
//charset
|
|
if( $page->gpLayout &&
|
|
isset($gpLayouts[$page->gpLayout]) &&
|
|
isset($gpLayouts[$page->gpLayout]['doctype'])
|
|
){
|
|
echo $gpLayouts[$page->gpLayout]['doctype'];
|
|
}
|
|
|
|
//title, keyords & description
|
|
$page_title = self::MetaTitle();
|
|
self::MetaKeywords($page_title);
|
|
self::MetaDescription($page_title);
|
|
|
|
if( !empty($page->TitleInfo['rel']) ){
|
|
echo "\n" . '<meta name="robots" content="' . $page->TitleInfo['rel'] . '" />';
|
|
}
|
|
|
|
echo "\n" . '<meta name="generator" content="' . \CMS_NAME_FULL . '" />';
|
|
}
|
|
|
|
|
|
/**
|
|
* Add the <title> tag to the page
|
|
* return the value
|
|
*
|
|
*/
|
|
public static function MetaTitle(){
|
|
global $page, $config;
|
|
|
|
$meta_title = '';
|
|
$page_title = '';
|
|
if( !empty($page->TitleInfo['browser_title']) ){
|
|
$page_title = $page->TitleInfo['browser_title'];
|
|
}elseif( !empty($page->label) ){
|
|
$page_title = strip_tags($page->label);
|
|
}elseif( isset($page->title) ){
|
|
$page_title = \gp\tool::GetBrowserTitle($page->title);
|
|
}
|
|
$meta_title .= $page_title;
|
|
if( !empty($page_title) && !empty($config['title']) ){
|
|
$meta_title .= ' - ';
|
|
}
|
|
$meta_title .= $config['title'];
|
|
|
|
$meta_title = \gp\tool\Plugins::Filter(
|
|
'MetaTitle',
|
|
[$meta_title, $page_title, $config['title']]
|
|
);
|
|
|
|
echo "\n" . '<title>' . strip_tags($meta_title) . '</title>';
|
|
return $page_title;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add the <meta name="keywords"> tag to the page
|
|
*
|
|
*/
|
|
public static function MetaKeywords($page_title){
|
|
global $page, $config;
|
|
|
|
if( count($page->meta_keywords) ){
|
|
$keywords = $page->meta_keywords;
|
|
}elseif( !empty($page->TitleInfo['keywords']) ){
|
|
$keywords = explode(',', $page->TitleInfo['keywords']);
|
|
}
|
|
$keywords[] = strip_tags($page_title);
|
|
$page->label .= "";
|
|
$keywords[] = strip_tags($page->label);
|
|
|
|
$site_keywords = explode(',', $config['keywords']);
|
|
$keywords = array_merge($keywords, $site_keywords);
|
|
$keywords = array_unique($keywords);
|
|
$keywords = array_filter($keywords);
|
|
|
|
echo "\n<meta name=\"keywords\" content=\"" . implode(', ', $keywords) . "\" />";
|
|
}
|
|
|
|
|
|
/**
|
|
* Add the <meta name="dscription"> tag to the page
|
|
*
|
|
*/
|
|
public static function MetaDescription($page_title){
|
|
global $page, $config;
|
|
|
|
$description = '';
|
|
if( !empty($page->meta_description) ){
|
|
$description .= $page->meta_description;
|
|
}elseif( !empty($page->TitleInfo['description']) ){
|
|
$description .= $page->TitleInfo['description'];
|
|
}else{
|
|
$description .= $page_title;
|
|
}
|
|
$description = self::EndPhrase($description);
|
|
|
|
if( !empty($config['desc']) ){
|
|
$description .= htmlspecialchars($config['desc']);
|
|
}
|
|
$description = trim($description);
|
|
|
|
if( !empty($description) ){
|
|
echo "\n" . '<meta name="description" content="' . $description . '" />';
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Prepare and output any inline Javascript for the current page
|
|
* @static
|
|
*/
|
|
public static function GetHead_InlineJS(){
|
|
global $page, $gp_titles;
|
|
|
|
if( isset($page->gp_index) &&
|
|
isset($gp_titles[$page->gp_index]['vis']) &&
|
|
$gp_titles[$page->gp_index]['vis'] == 'private'
|
|
){
|
|
$page->jQueryCode .= '$("html").addClass("isPrivate");' . "\n";
|
|
}
|
|
|
|
if( \gp\tool::LoggedIn() && $page->pagetype !== 'admin_display' ){
|
|
$page->jQueryCode .= '$gp.HideAdminUI.init();' . "\n";
|
|
// get available classes
|
|
$avail_classes = \gp\admin\Settings\Classes::GetClasses();
|
|
$avail_classes = \gp\tool\Plugins::Filter('AvailableClasses', [$avail_classes]);
|
|
$page->head_script .= "\n" . 'var gp_avail_classes = ' . json_encode($avail_classes) . ';';
|
|
}
|
|
|
|
// get customizer js vars
|
|
$layout_js_vars = self::GetLayoutJsVars();
|
|
// debug('$layout_js_vars = <em>' . $layout_js_vars . '</em>');
|
|
|
|
ob_start();
|
|
|
|
echo $layout_js_vars;
|
|
|
|
echo $page->head_script . "\n";
|
|
|
|
if( !empty($page->jQueryCode) ){
|
|
echo '$(function(){' . "\n";
|
|
echo $page->jQueryCode . "\n";
|
|
echo '});';
|
|
}
|
|
|
|
$inline = ob_get_clean();
|
|
$inline = ltrim($inline);
|
|
|
|
echo "\n" . '<script type="text/javascript">' . "\n" . $inline . "\n" . '</script>' . "\n";
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Add language values to the current page
|
|
* @static
|
|
*/
|
|
public static function GetHead_Lang(){
|
|
global $langmessage;
|
|
|
|
if( !count(self::$lang_values) ){
|
|
return;
|
|
}
|
|
|
|
echo "\n" . '<script type="text/javascript">';
|
|
echo 'var gplang = {';
|
|
$comma = '';
|
|
foreach(self::$lang_values as $from_key => $to_key){
|
|
echo $comma;
|
|
echo $to_key . ':"' . str_replace(['\\', '"'], ['\\\\', '\"'], $langmessage[$from_key]) . '"';
|
|
$comma = ',';
|
|
}
|
|
echo "}; </script>";
|
|
}
|
|
|
|
|
|
/**
|
|
* Prepare and output the Javascript for the current page
|
|
* @static
|
|
*/
|
|
public static function GetHead_JS($scripts){
|
|
global $page, $config;
|
|
|
|
$combine = $config['combinejs'] && !\gp\tool::loggedIn() && ($page->pagetype !== 'admin_display');
|
|
$scripts = self::GetHead_CDN('js', $scripts);
|
|
|
|
//just local jquery
|
|
if( !count($page->head_js) && count($scripts) === 1 && isset($scripts['jquery']) ){
|
|
echo '<!-- jquery_placeholder ' . \gp_random . ' -->';
|
|
return;
|
|
}
|
|
|
|
if( !$combine || $page->head_force_inline ){
|
|
echo "\n<script type=\"text/javascript\">\n";
|
|
\gp\tool::jsStart();
|
|
echo "\n</script>";
|
|
}
|
|
|
|
if( is_array($page->head_js) ){
|
|
$scripts += $page->head_js; //other js files
|
|
}else{
|
|
trigger_error('$page->head_js is not an array');
|
|
}
|
|
|
|
Output\Assets::CombineFiles($scripts, 'js', $combine);
|
|
}
|
|
|
|
|
|
/**
|
|
* Prepare and output the css for the current page
|
|
* @static
|
|
*/
|
|
public static function GetHead_CSS($to_add){
|
|
global $page, $config, $dataDir;
|
|
|
|
$scripts = [];
|
|
$to_add = self::GetHead_CDN('css', $to_add);
|
|
$scripts = Output\Assets::MergeScripts($scripts, $to_add);
|
|
|
|
|
|
if( isset($page->css_user) ){
|
|
$scripts = Output\Assets::MergeScripts($scripts, $page->css_user);
|
|
}
|
|
|
|
// add theme css
|
|
if( !empty($page->theme_name) && $page->get_theme_css === true ){
|
|
$scripts = Output\Assets::MergeScripts($scripts, Output\Assets::LayoutStyleFiles());
|
|
}
|
|
|
|
//styles that need to override admin.css should be added to $page->css_admin;
|
|
if( isset($page->css_admin) ){
|
|
$scripts = Output\Assets::MergeScripts($scripts, $page->css_admin);
|
|
}
|
|
|
|
// disable 'combine css' if 'create_css_sourcemaps' is set to true in /gpconfig.php
|
|
$combinecss = \create_css_sourcemaps ? false : $config['combinecss'];
|
|
|
|
Output\Assets::CombineFiles($scripts, 'css', $combinecss);
|
|
}
|
|
|
|
|
|
/**
|
|
* Add CDN hosted resources to the page
|
|
*
|
|
*/
|
|
public static function GetHead_CDN($type, $scripts){
|
|
global $config;
|
|
|
|
if( empty($config['cdn']) ){
|
|
return $scripts;
|
|
}
|
|
|
|
$cdn = $config['cdn'];
|
|
|
|
foreach($scripts as $key => $script_info){
|
|
|
|
if( !isset($script_info['cdn']) || !isset($script_info['cdn'][$cdn]) ){
|
|
continue;
|
|
}
|
|
|
|
$cdn_url = $script_info['cdn'][$cdn];
|
|
|
|
//remove packages
|
|
if( isset($script_info['package']) ){
|
|
foreach($scripts as $_key => $_info){
|
|
if( isset($_info['package']) && $_info['package'] == $script_info['package'] ){
|
|
unset($scripts[$_key]);
|
|
}
|
|
}
|
|
}
|
|
unset($scripts[$key]);
|
|
|
|
echo Output\Assets::FormatAsset($type,$cdn_url);
|
|
}
|
|
|
|
return $scripts;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the path for the custom css/scss/less file
|
|
*
|
|
*/
|
|
public static function CustomStyleFile($layout, $style_type){
|
|
global $dataDir;
|
|
|
|
if( $style_type == 'scss' ){
|
|
return $dataDir . '/data/_layouts/' . $layout . '/custom.scss';
|
|
}
|
|
|
|
return $dataDir . '/data/_layouts/' . $layout . '/custom.css';
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the path for the customizer css/scss/less file
|
|
*
|
|
* @since 5.2
|
|
*/
|
|
public static function CustomizerStyleFile($layout, $style_type){
|
|
global $dataDir;
|
|
|
|
if( $style_type == 'scss' ){
|
|
return $dataDir . '/data/_layouts/' . $layout . '/customizer.scss';
|
|
}
|
|
|
|
return $dataDir . '/data/_layouts/' . $layout . '/customizer.css';
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the path for the custom layout config file
|
|
*
|
|
* @since 5.2
|
|
*/
|
|
public static function LayoutConfigFile($layout){
|
|
global $dataDir;
|
|
|
|
return $dataDir . '/data/_layouts/' . $layout . '/config.php';
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the filetype of the style.* file
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function StyleType($dir){
|
|
|
|
$types = ['less','scss'];
|
|
|
|
foreach($types as $type){
|
|
$path = $dir . '/style.'.$type;
|
|
if( file_exists($path) ){
|
|
return $type;
|
|
}
|
|
}
|
|
return 'css';
|
|
}
|
|
|
|
|
|
/**
|
|
* Determines whether the passed directory qualifies as layout
|
|
* by checking whether a style.css, style.less or style.css file exists
|
|
* @return boolean
|
|
*/
|
|
public static function IsLayoutDir($dir){
|
|
|
|
$types = ['less','scss','css'];
|
|
|
|
foreach($types as $type){
|
|
$path = $dir . '/style.' . $type;
|
|
if( file_exists($path) ){
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Complete the response by adding final content to the <head> of the document
|
|
* @static
|
|
* @since 2.4.1
|
|
* @param string $buffer html content
|
|
* @return string finalized response
|
|
*/
|
|
public static function BufferOut($buffer){
|
|
global $config;
|
|
|
|
//add error notice if there was a fatal error
|
|
if( !ini_get('display_errors') ){
|
|
$last_error = self::LastFatal();
|
|
if( !empty($last_error) ){
|
|
self::RecordFatal($last_error);
|
|
$buffer .= self::FatalMessage($last_error);
|
|
}
|
|
}
|
|
|
|
//remove lock
|
|
if( defined('gp_has_lock') && \gp_has_lock ){
|
|
\gp\tool\Files::Unlock('write', \gp_random);
|
|
}
|
|
|
|
//make sure whe have a complete html request
|
|
$placeholder = '<!-- get_head_placeholder ' . \gp_random . ' -->';
|
|
if( strpos($buffer,$placeholder) === false ){
|
|
return $buffer;
|
|
}
|
|
|
|
$replacements = [];
|
|
|
|
//performace stats
|
|
if( class_exists('admin_tools') ){
|
|
$replacements = self::PerformanceStats();
|
|
}
|
|
|
|
//head content
|
|
//add css to bottom of <body>
|
|
if( \load_css_in_body ){
|
|
$buffer = self::AddToBody($buffer, self::$head_css);
|
|
$replacements[$placeholder] = self::$head_content;
|
|
}else{
|
|
$replacements[$placeholder] = self::$head_css . self::$head_content;
|
|
}
|
|
|
|
//add js to bottom of <body>
|
|
$buffer = self::AddToBody($buffer, self::$head_js);
|
|
|
|
//add jquery if needed
|
|
$placeholder = '<!-- jquery_placeholder ' . \gp_random . ' -->';
|
|
$replacement = '';
|
|
if( !empty(self::$head_js) || stripos($buffer, '<script') !== false ){
|
|
$replacement = Output\Assets::FormatAsset('js',\gp\tool::GetDir('/include/thirdparty/js/jquery.js')); // TODO: restore this line
|
|
}
|
|
|
|
$replacements[$placeholder] = $replacement;
|
|
|
|
//messages
|
|
$pos = strpos($buffer, '<!-- message_start ' . \gp_random . ' -->');
|
|
$len = strpos($buffer, '<!-- message_end -->') - $pos;
|
|
if( $pos && $len ){
|
|
$replacement = GetMessages(false);
|
|
$buffer = substr_replace($buffer, $replacement, $pos, $len + 20);
|
|
}
|
|
|
|
return str_replace( array_keys($replacements), array_values($replacements), $buffer);
|
|
}
|
|
|
|
|
|
/**
|
|
* Add content to the html document before the </body> tag
|
|
*
|
|
*/
|
|
public static function AddToBody($buffer, $add_string){
|
|
|
|
if( empty($add_string) ){
|
|
return $buffer;
|
|
}
|
|
|
|
$pos_body = stripos($buffer, '</body');
|
|
if( $pos_body !== false ){
|
|
return substr_replace($buffer, "\n" . $add_string . "\n", $pos_body, 0);
|
|
}
|
|
|
|
return $buffer;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return the message displayed when a fatal error has been caught
|
|
*
|
|
*/
|
|
public static function FatalMessage($error_details){
|
|
|
|
$message = '<p>Oops, an error occurred while generating this page.<p>';
|
|
|
|
if( !\gp\tool::LoggedIn() ){
|
|
|
|
//reload non-logged in users automatically if there were catchable errors
|
|
if( !empty(self::$catchable) ){
|
|
$message .= 'Reloading... <script type="text/javascript">'
|
|
. 'window.setTimeout(function(){window.location.href = '
|
|
. 'window.location.href},1000);</script>';
|
|
}else{
|
|
$message .= '<p>If you are the site administrator, you can troubleshoot '
|
|
. 'the problem by changing php\'s display_errors setting to 1 in '
|
|
. 'the gpconfig.php file.</p><p>If the problem is being caused by an addon, '
|
|
. 'you may also be able to bypass the error by enabling ' . \CMS_NAME . '\'s '
|
|
. 'safe mode in the gpconfig.php file.</p><p>More information is available '
|
|
. 'in the <a href="' . \CMS_DOMAIN . '/Docs/Main/Troubleshooting">Documentation</a>.'
|
|
. '</p><p><a href="?">Reload this page to continue</a>.</p>';
|
|
}
|
|
|
|
return $message;
|
|
}
|
|
|
|
$message .= '<h3>Error Details</h3>'
|
|
.pre($error_details)
|
|
. '<p><a href="?">Reload this page</a></p>'
|
|
. '<p style="font-size:90%">Note: Error details are only '
|
|
. 'displayed for logged in administrators</p>'
|
|
. \gp\tool::ErrorBuffer(true, false);
|
|
|
|
return $message;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Determine if a fatal error has been fired
|
|
* @return array
|
|
*/
|
|
public static function LastFatal(){
|
|
$fatal_errors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR];
|
|
$last_error = error_get_last();
|
|
if( is_array($last_error) && in_array($last_error['type'], $fatal_errors) ){
|
|
return $last_error;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Record fatal errors in /data/_site/ so we can prevent subsequent requests from having the same issue
|
|
*
|
|
*/
|
|
public static function RecordFatal($last_error){
|
|
global $config, $addon_current_id, $addonFolderName;
|
|
|
|
$last_error['request'] = $_SERVER['REQUEST_URI'];
|
|
if( $addon_current_id ){
|
|
$last_error['addon_name'] = $config['addons'][$addonFolderName]['name'];
|
|
$last_error['addon_id'] = $addon_current_id;
|
|
}
|
|
|
|
$last_error['file'] = realpath($last_error['file']);//may be redundant
|
|
showError(
|
|
$last_error['type'],
|
|
$last_error['message'],
|
|
$last_error['file'],
|
|
$last_error['line'],
|
|
false
|
|
); //send error to logger
|
|
|
|
if( empty(self::$catchable) ){
|
|
return;
|
|
}
|
|
|
|
$last_error['time'] = time();
|
|
$last_error['request_method'] = $_SERVER['REQUEST_METHOD'];
|
|
if( !empty($last_error['file']) ){
|
|
$last_error['file_modified'] = filemtime($last_error['file']);
|
|
$last_error['file_size'] = filesize($last_error['file']);
|
|
}
|
|
|
|
$content = json_encode($last_error);
|
|
$temp = array_reverse(self::$catchable);
|
|
|
|
foreach($temp as $filepath => $info){
|
|
|
|
\gp\tool\Files::Save($filepath,$content);
|
|
|
|
if( $info['catchable_type'] == 'exec' ){
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Return Performance Stats about the current request
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function PerformanceStats(){
|
|
|
|
$stats = [];
|
|
|
|
if( function_exists('memory_get_peak_usage') ){
|
|
$stats['<span cms-memory-usage>?</span>'] = \gp\admin\Tools::FormatBytes(memory_get_usage());
|
|
$stats['<span cms-memory-max>?</span>'] = \gp\admin\Tools::FormatBytes(memory_get_peak_usage());
|
|
}
|
|
|
|
if( isset($_SERVER['REQUEST_TIME_FLOAT']) ){
|
|
$time = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
|
|
}else{
|
|
$time = microtime(true) - gp_start_time;
|
|
}
|
|
|
|
$stats['<span cms-seconds>?</span>'] = round($time, 3);
|
|
$stats['<span cms-ms>?</span>'] = round($time * 1000);
|
|
|
|
return $stats;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return true if the user agent is a search engine bot
|
|
* Detection is rudimentary and shouldn't be relied on
|
|
* @return bool
|
|
*/
|
|
public static function DetectBot(){
|
|
$user_agent =& $_SERVER['HTTP_USER_AGENT'];
|
|
return (bool)preg_match('#bot|yahoo\! slurp|ask jeeves|ia_archiver|spider|crawler#i', $user_agent);
|
|
}
|
|
|
|
/**
|
|
* Return true if the current page is the home page
|
|
*/
|
|
public static function is_front_page(){
|
|
global $config, $page;
|
|
return $page->gp_index == $config['homepath_key'];
|
|
}
|
|
|
|
|
|
/**
|
|
* Outputs the sitemap link, admin login/logout link, powered by link and messages
|
|
* @static
|
|
*/
|
|
public static function GetAdminLink($messages=true){
|
|
self::GetSitemapLink(); // as of 5.2-rc
|
|
echo ' ';
|
|
self::GetLoginLink(); // as of 5.2-rc
|
|
echo ' ';
|
|
self::GetPoweredByLink(); // as of 5.2-rc
|
|
|
|
\gp\tool\Plugins::Action('GetAdminLink');
|
|
|
|
if( $messages ){
|
|
echo GetMessages();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Outputs only the sitemap link
|
|
* as of 5.2-rc
|
|
* @static
|
|
*/
|
|
public static function GetSitemapLink(){
|
|
global $config, $langmessage, $page;
|
|
|
|
if( !isset($config['showsitemap']) || $config['showsitemap'] ){
|
|
echo ' <span class="sitemap_link">';
|
|
echo \gp\tool::Link(
|
|
'Special_Site_Map',
|
|
$langmessage['site_map']
|
|
);
|
|
\gp\tool\Plugins::Action('GetSitemapLink');
|
|
echo '</span>';
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Outputs only the login/logout link
|
|
* as of 5.2-rc
|
|
* @static
|
|
*/
|
|
public static function GetLoginLink($force_show=false){
|
|
global $config, $langmessage, $page;
|
|
|
|
if( $force_show || !isset($config['showlogin']) || $config['showlogin'] ){
|
|
echo '<span class="login_link">';
|
|
if( \gp\tool::LoggedIn() ){
|
|
echo \gp\tool::Link(
|
|
$page->title,
|
|
$langmessage['logout'],
|
|
'cmd=logout',
|
|
['data-cmd' => 'cnreq', 'rel' => 'nofollow']
|
|
);
|
|
}else{
|
|
echo \gp\tool::Link(
|
|
'Admin',
|
|
$langmessage['login'],
|
|
'file=' . rawurlencode($page->title),
|
|
['data-cmd' => 'login', 'rel' => 'nofollow']
|
|
);
|
|
}
|
|
\gp\tool\Plugins::Action('GetLoginLink');
|
|
echo '</span>';
|
|
}
|
|
}
|
|
|
|
|
|
public static function AdminLinkGadget(){
|
|
self::GetAdminLink(false);
|
|
}
|
|
|
|
|
|
public static function LoginLinkGadget(){
|
|
self::GetLoginLink(true);
|
|
}
|
|
|
|
|
|
/**
|
|
* Outputs only the powered_by link
|
|
* as of 5.2-rc
|
|
* @static
|
|
*/
|
|
public static function GetPoweredByLink($always_show=false){
|
|
global $config;
|
|
|
|
if( !isset($config['showgplink']) || $config['showgplink'] ){
|
|
if( self::is_front_page() || $always_show ){
|
|
echo '<span id="powered_by_link">';
|
|
echo 'Powered by <a href="' . \CMS_DOMAIN . '" target="_blank">' . \CMS_NAME . '</a>';
|
|
\gp\tool\Plugins::Action('GetPoweredByLink');
|
|
echo '</span>';
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Add punctuation to the end of a string if it isn't already punctuated.
|
|
* Looks for !?.,;: characters
|
|
*
|
|
* @static
|
|
* @since 2.4RC1
|
|
*/
|
|
public static function EndPhrase($string){
|
|
$string = trim($string);
|
|
if( empty($string) ){
|
|
return $string;
|
|
}
|
|
$len = strspn($string, '!?.,;:', -1);
|
|
if( $len == 0 ){
|
|
$string .= '.';
|
|
}
|
|
return $string . ' ';
|
|
}
|
|
|
|
|
|
public static function RunOut(){
|
|
global $langmessage, $page;
|
|
|
|
$page->RunScript();
|
|
|
|
//prepare the admin content
|
|
if( \gp\tool::LoggedIn() ){
|
|
\gp\admin\Tools::AdminHtml();
|
|
}
|
|
|
|
//decide how to send the content
|
|
self::Prep();
|
|
switch(\gp\tool::RequestType()){
|
|
|
|
// <a data-cmd="admin_box">
|
|
case 'flush':
|
|
self::Flush();
|
|
break;
|
|
|
|
// remote request
|
|
// file browser
|
|
case 'body':
|
|
\gp\tool::CheckTheme();
|
|
self::BodyAsHTML();
|
|
break;
|
|
|
|
case 'admin':
|
|
self::AdminHtml();
|
|
break;
|
|
|
|
// <a data-cmd="gpajax">
|
|
// <a data-cmd="gpabox">
|
|
// <input data-cmd="gpabox">
|
|
case 'json':
|
|
\gp\tool::CheckTheme();
|
|
\gp\tool\Output\Ajax::Response();
|
|
break;
|
|
|
|
case 'content':
|
|
self::Content();
|
|
break;
|
|
|
|
default:
|
|
\gp\tool::CheckTheme();
|
|
self::Template();
|
|
break;
|
|
}
|
|
|
|
// if logged in, don't send 304 response
|
|
if( \gp\tool::LoggedIn() ){
|
|
//empty edit links if there isn't a layout
|
|
if( !$page->gpLayout ){
|
|
self::$editlinks = '';
|
|
}
|
|
return;
|
|
}
|
|
|
|
// attempt to send 304 response
|
|
if( $page->fileModTime > 0 ){
|
|
global $wbMessageBuffer;
|
|
$len = ob_get_length();
|
|
$etag = \gp\tool::GenEtag(
|
|
$page->fileModTime,
|
|
$len,
|
|
json_encode($wbMessageBuffer),
|
|
self::$head_content,
|
|
self::$head_js
|
|
);
|
|
\gp\tool::Send304($etag);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Add one or more components to the page. Output the <script> and/or <style> immediately
|
|
* @param string $names comma separated list of components
|
|
*
|
|
*/
|
|
public static function GetComponents($names=''){
|
|
$scripts = \gp\tool\Output\Combine::ScriptInfo($names);
|
|
|
|
$scripts['css'] = self::GetHead_CDN('css', $scripts['css']);
|
|
Output\Assets::CombineFiles($scripts['css'], 'css', false);
|
|
|
|
$scripts['js'] = self::GetHead_CDN('js', $scripts['js']);
|
|
Output\Assets::CombineFiles($scripts['js'], 'js', false);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
namespace{
|
|
class gpOutput extends gp\tool\Output{}
|
|
}
|