509 lines
12 KiB
PHP
509 lines
12 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace gp\tool{
|
||
|
|
||
|
defined('is_running') or die('Not an entry point...');
|
||
|
|
||
|
|
||
|
class Plugins{
|
||
|
|
||
|
/**
|
||
|
* Holds the configuration values of the current plugin if there is an active plugin
|
||
|
*
|
||
|
*/
|
||
|
public static $current = false;
|
||
|
|
||
|
private static $stack = [];
|
||
|
|
||
|
public static $curr_page_calls = [];
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Aliases of gpPlugin_incl()
|
||
|
* @deprecated 3.5.3
|
||
|
*/
|
||
|
public static function incl($file){
|
||
|
return gpPlugin_incl($file);
|
||
|
}
|
||
|
|
||
|
public static function inc($file){
|
||
|
return gpPlugin_incl($file);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Add a css file to the page
|
||
|
* @since 4.0
|
||
|
* @param string $file The path of the css file relative to the addon folder
|
||
|
* @param bool $combine Set to false to keep the file from being combined with other css files
|
||
|
*/
|
||
|
public static function css($file, $combine=true){
|
||
|
global $page;
|
||
|
|
||
|
$file = \gp\tool::WinPath($file);
|
||
|
|
||
|
if( $combine ){
|
||
|
$page->css_admin[] = self::$current['code_folder_part'] . '/' . ltrim($file, '/');
|
||
|
return self::$current['code_folder_part'] . '/' . ltrim($file, '/');
|
||
|
}
|
||
|
|
||
|
//less or scss file
|
||
|
$ext = \gp\tool::Ext($file);
|
||
|
if( $ext === 'less' || $ext === 'scss' ){
|
||
|
$full_path = self::$current['code_folder_full'] . '/' . ltrim($file, '/');
|
||
|
$path = \gp\tool\Output\Css::Cache($full_path, $ext);
|
||
|
}else{
|
||
|
$file = self::AddCacheBuster($file);
|
||
|
$path = self::$current['code_folder_part'] . '/' . ltrim($file, '/');
|
||
|
}
|
||
|
|
||
|
if( $path !== false ){
|
||
|
$page->head .= "\n" . '<link rel="stylesheet" type="text/css" href="' . \gp\tool::GetDir($path) . '"/>';
|
||
|
}
|
||
|
|
||
|
return $path;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Add a js file to the page
|
||
|
* @since 4.0
|
||
|
* @param string $file The path of the js file relative to the addon folder
|
||
|
* @param bool $combine Set to false to keep the file from being combined with other js files
|
||
|
*/
|
||
|
public static function js($file, $combine=true){
|
||
|
global $page;
|
||
|
|
||
|
$file = \gp\tool::WinPath($file);
|
||
|
|
||
|
if( $combine ){
|
||
|
$page->head_js[] = self::$current['code_folder_part'] . '/' . ltrim($file, '/');
|
||
|
}else{
|
||
|
$file = self::AddCacheBuster($file);
|
||
|
$url = self::$current['code_folder_rel'].'/'.ltrim($file,'/');
|
||
|
$page->head .= "\n" . '<script type="text/javascript" src="' . $url . '"></script>';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Add a cache-busting query string to the end of the file if it doesn't already have a query string
|
||
|
*
|
||
|
*/
|
||
|
public static function AddCacheBuster($file){
|
||
|
if( strpos('?', $file) == false ){
|
||
|
$full = self::$current['code_folder_full'] . '/' . ltrim($file, '/');
|
||
|
if( file_exists($full) ){
|
||
|
$file .= '?' . filemtime($full);
|
||
|
}
|
||
|
}
|
||
|
return $file;
|
||
|
}
|
||
|
|
||
|
|
||
|
public static function GetDir($path='', $ampersands=false){
|
||
|
$path = self::$current['code_folder_part'] . '/' . ltrim($path, '/');
|
||
|
return \gp\tool::GetDir($path, $ampersands);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Similar to php's register_shutdown_function()
|
||
|
* Will keep track of the active plugin and make sure global path variables are set properly before callting $function
|
||
|
* Example: \gp\tool\Plugins::RegisterShutdown(array('class_name','method_name')); or \gp\tool\Plugins::RegisterShutdown(array('class_name','method_name'),'argument1'....);
|
||
|
*
|
||
|
*/
|
||
|
public static function RegisterShutdown(){
|
||
|
global $addonFolderName;
|
||
|
if( gp_safe_mode ){
|
||
|
return;
|
||
|
}
|
||
|
$args = func_get_args();
|
||
|
register_shutdown_function(['\\gp\\tool\\Plugins','ShutdownFunction'], $addonFolderName, $args);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Handle functions passed to \gp\tool\Plugins::RegisterShutdown()
|
||
|
* This function should not be called directly.
|
||
|
*/
|
||
|
public static function ShutdownFunction($addonFolderName,$args){
|
||
|
|
||
|
if( gp_safe_mode ){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( !is_array($args) || count($args) < 1 ){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
self::SetDataFolder($addonFolderName);
|
||
|
|
||
|
$function = array_shift($args);
|
||
|
|
||
|
if( count($args) > 0 ){
|
||
|
call_user_func_array($function, $args);
|
||
|
}else{
|
||
|
call_user_func($function);
|
||
|
}
|
||
|
|
||
|
self::ClearDataFolder();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Similar to wordpress apply_filters_ref_array()
|
||
|
*
|
||
|
*/
|
||
|
public static function Filter($hook, $args=[]){
|
||
|
global $gp_hooks;
|
||
|
|
||
|
self::$curr_page_calls[] = 'Filter:' . $hook;
|
||
|
|
||
|
if( !self::HasHook($hook) ){
|
||
|
if( isset($args[0]) ){
|
||
|
return $args[0];
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
foreach($gp_hooks[$hook] as $hook_info){
|
||
|
$args[0] = self::ExecHook($hook, $hook_info, $args);
|
||
|
}
|
||
|
|
||
|
if( isset($args[0]) ){
|
||
|
return $args[0];
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
public static function OneFilter($hook, $args=[], $addon=false){
|
||
|
global $gp_hooks;
|
||
|
|
||
|
self::$curr_page_calls[] = 'OneFilter:' . $hook;
|
||
|
|
||
|
if( !self::HasHook($hook) ){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if( $addon === false ){
|
||
|
$hook_info = end($gp_hooks[$hook]);
|
||
|
return self::ExecHook($hook, $hook_info, $args);
|
||
|
}
|
||
|
|
||
|
foreach($gp_hooks[$hook] as $addon_key => $hook_info){
|
||
|
if( $addon_key === $addon ){
|
||
|
return self::ExecHook($hook, $hook_info, $args);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
public static function Action($hook, $args=[]){
|
||
|
global $gp_hooks;
|
||
|
|
||
|
self::$curr_page_calls[] = 'Action:' . $hook;
|
||
|
|
||
|
if( !self::HasHook($hook) ){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
foreach($gp_hooks[$hook] as $hook_info){
|
||
|
self::ExecHook($hook, $hook_info, $args);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Check to see if there area any hooks matching $hook
|
||
|
* @param string $hook The name of the hook
|
||
|
* @return bool
|
||
|
*
|
||
|
*/
|
||
|
public static function HasHook($hook){
|
||
|
global $gp_hooks;
|
||
|
if( empty($gp_hooks) || empty($gp_hooks[$hook]) ){
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public static function ArgReturn($args){
|
||
|
if( is_array($args) && isset($args[0]) ){
|
||
|
return $args[0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Execute the php code associated with a $hook
|
||
|
* @param string $hook
|
||
|
* @param array $hook_info
|
||
|
* @param array $args
|
||
|
*
|
||
|
*/
|
||
|
public static function ExecHook($hook, $info, $args=[]){
|
||
|
global $dataDir, $gp_current_hook;
|
||
|
|
||
|
if( gp_safe_mode ){
|
||
|
if( isset($args[0]) ){
|
||
|
return $args[0];
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( !is_array($args) ){
|
||
|
$args = [$args];
|
||
|
}
|
||
|
$gp_current_hook[] = $hook;
|
||
|
|
||
|
//value
|
||
|
if( !empty($info['value']) ){
|
||
|
$args[0] = $info['value'];
|
||
|
}
|
||
|
|
||
|
$args = \gp\tool\Output::ExecInfo($info, $args);
|
||
|
|
||
|
array_pop( $gp_current_hook );
|
||
|
if( isset($args[0]) ){
|
||
|
return $args[0];
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Set global path variables for the current addon
|
||
|
* @param string $addon_key Key used to identify a plugin uniquely in the configuration
|
||
|
*
|
||
|
*/
|
||
|
public static function SetDataFolder($addon_key){
|
||
|
global $dataDir, $config;
|
||
|
global $addonDataFolder, $addonCodeFolder; //deprecated
|
||
|
global $addonRelativeCode, $addonRelativeData, $addonPathData, $addonPathCode;
|
||
|
global $addonFolderName, $addon_current_id, $addon_current_version;
|
||
|
|
||
|
if( !isset($config['addons'][$addon_key]) ){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self::StackPush();
|
||
|
self::$current = self::GetAddonConfig($addon_key);
|
||
|
|
||
|
$addonFolderName = $addon_key;
|
||
|
$addon_current_id = self::$current['id'];
|
||
|
$addon_current_version = self::$current['version'];
|
||
|
$addonPathCode = $addonCodeFolder = self::$current['code_folder_full'];
|
||
|
$addonPathData = $addonDataFolder = self::$current['data_folder_full'];
|
||
|
$addonRelativeCode = self::$current['code_folder_rel'];
|
||
|
$addonRelativeData = self::$current['data_folder_rel'];
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return settings of addon defined by $addon_key
|
||
|
*
|
||
|
*/
|
||
|
public static function GetAddonConfig($addon_key){
|
||
|
global $config, $dataDir;
|
||
|
|
||
|
if( !array_key_exists($addon_key, $config['addons']) ){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$addon_config = $config['addons'][$addon_key];
|
||
|
if( !is_array($addon_config) ){
|
||
|
trigger_error('Corrupted configuration for addon: ' . $addon_key); //.pre($config['addons']));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$addon_config += [
|
||
|
'version' => false,
|
||
|
'id' => false,
|
||
|
'data_folder' => $addon_key,
|
||
|
'order' => false,
|
||
|
'code_folder_part' => '/data/_addoncode/' . $addon_key,
|
||
|
'name' => $addon_key
|
||
|
];
|
||
|
|
||
|
//data folder
|
||
|
$addon_config['data_folder_part'] = '/data/_addondata/' . $addon_config['data_folder'];
|
||
|
$addon_config['data_folder_full'] = $dataDir . $addon_config['data_folder_part'];
|
||
|
$addon_config['data_folder_rel'] = \gp\tool::GetDir($addon_config['data_folder_part']);
|
||
|
|
||
|
|
||
|
// Code folder
|
||
|
//$addon_config['code_folder_part'] = $addon_config['code_folder'].'/'.$addon_key;
|
||
|
$addon_config['code_folder_full'] = $dataDir.$addon_config['code_folder_part'];
|
||
|
$addon_config['code_folder_rel'] = \gp\tool::GetDir($addon_config['code_folder_part']);
|
||
|
|
||
|
return $addon_config;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* If there's a current addon folder or addon id, push it onto the stack
|
||
|
*
|
||
|
*/
|
||
|
public static function StackPush(){
|
||
|
global $addonFolderName, $addon_current_id;
|
||
|
|
||
|
if( !$addon_current_id && !$addonFolderName ){
|
||
|
return;
|
||
|
}
|
||
|
self::$stack[] = ['folder' => $addonFolderName, 'id' => $addon_current_id];
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Reset global path variables
|
||
|
*/
|
||
|
public static function ClearDataFolder(){
|
||
|
global $addonDataFolder, $addonCodeFolder; //deprecated
|
||
|
global $addonRelativeCode, $addonRelativeData, $addonPathData, $addonPathCode;
|
||
|
global $addonFolderName, $addon_current_id, $addon_current_version;
|
||
|
|
||
|
self::$current = [];
|
||
|
$addonFolderName = false;
|
||
|
$addonDataFolder = false;
|
||
|
$addonCodeFolder = false;
|
||
|
$addonRelativeCode = false;
|
||
|
$addonRelativeData = false;
|
||
|
$addonPathData = false;
|
||
|
$addon_current_id = false;
|
||
|
$addon_current_version = false;
|
||
|
|
||
|
//Make the most recent addon folder or addon id in the stack the current addon
|
||
|
if( count(self::$stack) > 0 ){
|
||
|
$info = array_pop(self::$stack);
|
||
|
if( $info['folder'] ){
|
||
|
self::SetDataFolder($info['folder']);
|
||
|
}elseif( $info['id'] ){
|
||
|
$addon_current_id = $info['id'];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get the addon_key of an addon by its id
|
||
|
* @static
|
||
|
* @param int $addon_id
|
||
|
* @return mixed Returns addon_key string if found, false otherwise
|
||
|
*
|
||
|
*/
|
||
|
public static function AddonFromId($addon_id){
|
||
|
global $config;
|
||
|
if( empty($config['addons']) ){
|
||
|
return false;
|
||
|
}
|
||
|
foreach($config['addons'] as $addon_key => $addon_info){
|
||
|
if( isset($addon_info['id']) && $addon_info['id'] == $addon_id ){
|
||
|
return $addon_key;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Checks if an addon is installed
|
||
|
* @since 5.2
|
||
|
* @param string $name - the addon name, very forgiving in terms of case, blanks, underscores and dashes
|
||
|
* @param mixed (string | number) $min_ver, optional minimum addon version
|
||
|
* @param mixed (string | number) $max_ver, optional maximum addon version
|
||
|
* @return mixed (array | boolean ) returns an array with name and version if the addon is installed, false otherwise
|
||
|
*/
|
||
|
public static function AddonInstalled($name, $min_ver=false, $max_ver=false){
|
||
|
global $config;
|
||
|
|
||
|
if( empty($config['addons']) ){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$requested = preg_replace('/[ _-]+/', '', strtolower($name));
|
||
|
|
||
|
foreach( $config['addons'] as $key => $data ){
|
||
|
$found = $data['name'];
|
||
|
$current = preg_replace('/[ _-]+/', '', strtolower($found));
|
||
|
|
||
|
if( $current != $requested ){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$current_ver = $data['version'];
|
||
|
|
||
|
$in_range = true;
|
||
|
if( !empty($min_ver) ){
|
||
|
$in_range = version_compare($current_ver, $min_ver, '>=');
|
||
|
}
|
||
|
if( !empty($max_ver) ){
|
||
|
$in_range = $in_range && version_compare($current_ver, $max_ver, '<=');
|
||
|
}
|
||
|
|
||
|
if( $in_range ){
|
||
|
return [ 'name' => $found, 'version' => $current_ver ];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get plugin configuration values
|
||
|
* @since 3.6
|
||
|
*
|
||
|
*/
|
||
|
public static function GetConfig(){
|
||
|
|
||
|
$file = self::$current['data_folder_full'] . '/_config.php';
|
||
|
return \gp\tool\Files::Get($file, 'config');
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get plugin configuration values
|
||
|
* @since 3.6
|
||
|
*
|
||
|
*/
|
||
|
public static function SaveConfig($config){
|
||
|
|
||
|
$file = self::$current['data_folder_full'] . '/_config.php';
|
||
|
|
||
|
if( \gp\tool\Files::SaveData($file, 'config', $config) ){
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
namespace{
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Include a file in the current plugin directory
|
||
|
* @param string $file File to include relative to the current plugin directory
|
||
|
* @since 3.5.3
|
||
|
*/
|
||
|
function gpPlugin_incl($file){
|
||
|
global $addonPathCode, $dataDir;
|
||
|
if( gp_safe_mode ){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
return IncludeScript($addonPathCode.'/'.$file); // return added in 5.0b3
|
||
|
}
|
||
|
|
||
|
|
||
|
class gpPlugin extends \gp\tool\Plugins{}
|
||
|
|
||
|
}
|
||
|
|
||
|
|