Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Q
question2answer
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
outils
question2answer
Commits
58fb33a4
Commit
58fb33a4
authored
Jan 12, 2017
by
Scott
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Coding style (base)
parent
5bc0177c
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
581 additions
and
550 deletions
+581
-550
qa-base.php
qa-include/qa-base.php
+581
-550
No files found.
qa-include/qa-base.php
View file @
58fb33a4
...
@@ -21,11 +21,11 @@
...
@@ -21,11 +21,11 @@
*/
*/
define
(
'QA_VERSION'
,
'1.7.4'
);
// also used as suffix for .js and .css requests
define
(
'QA_VERSION'
,
'1.7.4'
);
// also used as suffix for .js and .css requests
define
(
'QA_BUILD_DATE'
,
'2016-03-14'
);
define
(
'QA_BUILD_DATE'
,
'2016-03-14'
);
/**
/**
* Autoloads some Q2A classes so it's possible to use them without adding a require_once first. From version 1.7 onwards.
* Autoloads some Q2A classes so it's possible to use them without adding a require_once first. From version 1.7 onwards.
* These loosely follow PHP-FIG's PSR-0 standard where faux namespaces are separated by underscores. This is being done
* These loosely follow PHP-FIG's PSR-0 standard where faux namespaces are separated by underscores. This is being done
* slowly and carefully to maintain backwards compatibility, and does not apply to plugins, themes, nor most of the core
* slowly and carefully to maintain backwards compatibility, and does not apply to plugins, themes, nor most of the core
...
@@ -36,105 +36,92 @@
...
@@ -36,105 +36,92 @@
* Classes are mapped to PHP files with the underscores converted to directory separators. The Q2A_Util_Debug class is in
* Classes are mapped to PHP files with the underscores converted to directory separators. The Q2A_Util_Debug class is in
* the file qa-include/Q2A/Util/Debug.php. A class named Q2A_Db_User_Messages would be in a file qa-include/Q2A/Db/User/Messages.php.
* the file qa-include/Q2A/Util/Debug.php. A class named Q2A_Db_User_Messages would be in a file qa-include/Q2A/Db/User/Messages.php.
*/
*/
function
qa_autoload
(
$class
)
function
qa_autoload
(
$class
)
{
{
if
(
strpos
(
$class
,
'Q2A_'
)
===
0
)
if
(
strpos
(
$class
,
'Q2A_'
)
===
0
)
require
QA_INCLUDE_DIR
.
strtr
(
$class
,
'_'
,
'/'
)
.
'.php'
;
require
QA_INCLUDE_DIR
.
strtr
(
$class
,
'_'
,
'/'
)
.
'.php'
;
}
}
spl_autoload_register
(
'qa_autoload'
);
spl_autoload_register
(
'qa_autoload'
);
// Execution section of this file - remainder contains function definitions
// Execution section of this file - remainder contains function definitions
qa_initialize_php
();
qa_initialize_php
();
qa_initialize_constants_1
();
qa_initialize_constants_1
();
if
(
defined
(
'QA_WORDPRESS_LOAD_FILE'
))
{
if
(
defined
(
'QA_WORDPRESS_LOAD_FILE'
))
{
// if relevant, load WordPress integration in global scope
// if relevant, load WordPress integration in global scope
require_once
QA_WORDPRESS_LOAD_FILE
;
require_once
QA_WORDPRESS_LOAD_FILE
;
}
}
elseif
(
defined
(
'QA_JOOMLA_LOAD_FILE'
))
{
elseif
(
defined
(
'QA_JOOMLA_LOAD_FILE'
))
{
// if relevant, load Joomla JConfig class into global scope
// if relevant, load Joomla JConfig class into global scope
require_once
QA_JOOMLA_LOAD_FILE
;
require_once
QA_JOOMLA_LOAD_FILE
;
}
}
qa_initialize_constants_2
();
qa_initialize_modularity
();
qa_register_core_modules
();
require_once
QA_INCLUDE_DIR
.
'qa-db.php'
;
qa_initialize_plugins
();
function
qa_initialize_plugins
()
{
qa_initialize_constants_2
();
$pluginManager
=
new
Q2A_Plugin_PluginManager
();
qa_initialize_modularity
();
$pluginManager
->
readAllPluginMetadata
s
();
qa_register_core_module
s
();
$pluginManager
->
loadPluginsBeforeDbInit
();
require_once
QA_INCLUDE_DIR
.
'qa-db.php'
;
qa_load_override_files
();
qa_db_allow_connect
();
qa_initialize_plugins
();
$pluginManager
->
loadPluginsAfterDbInit
();
qa_load_override_files
();
}
// Version comparison functions
// Version comparison functions
/**
/**
* Converts the $version string (e.g. 1.6.2.2) to a floating point that can be used for greater/lesser comparisons
* Converts the $version string (e.g. 1.6.2.2) to a floating point that can be used for greater/lesser comparisons
* (PHP's version_compare() function is not quite suitable for our needs)
* (PHP's version_compare() function is not quite suitable for our needs)
*/
*/
function
qa_version_to_float
(
$version
)
function
qa_version_to_float
(
$version
)
{
{
$value
=
0.0
;
$value
=
0.0
;
if
(
preg_match
(
'/[0-9\.]+/'
,
$version
,
$matches
))
{
if
(
preg_match
(
'/[0-9\.]+/'
,
$version
,
$matches
))
{
$parts
=
explode
(
'.'
,
$matches
[
0
]);
$parts
=
explode
(
'.'
,
$matches
[
0
]);
$units
=
1.0
;
$units
=
1.0
;
foreach
(
$parts
as
$part
)
{
foreach
(
$parts
as
$part
)
{
$value
+=
min
(
$part
,
999
)
*
$units
;
$value
+=
min
(
$part
,
999
)
*
$units
;
$units
/=
1000
;
$units
/=
1000
;
}
}
}
}
return
$value
;
return
$value
;
}
}
/**
/**
* Returns true if the current Q2A version is lower than $version, if both are valid version strings for qa_version_to_float()
* Returns true if the current Q2A version is lower than $version, if both are valid version strings for qa_version_to_float()
*/
*/
function
qa_qa_version_below
(
$version
)
function
qa_qa_version_below
(
$version
)
{
{
$minqa
=
qa_version_to_float
(
$version
);
$minqa
=
qa_version_to_float
(
$version
);
$thisqa
=
qa_version_to_float
(
QA_VERSION
);
$thisqa
=
qa_version_to_float
(
QA_VERSION
);
return
$minqa
&&
$thisqa
&&
(
$thisqa
<
$minqa
)
;
return
$minqa
&&
$thisqa
&&
$thisqa
<
$minqa
;
}
}
/**
/**
* Returns true if the current PHP version is lower than $version, if both are valid version strings for qa_version_to_float()
* Returns true if the current PHP version is lower than $version, if both are valid version strings for qa_version_to_float()
*/
*/
function
qa_php_version_below
(
$version
)
function
qa_php_version_below
(
$version
)
{
{
$minphp
=
qa_version_to_float
(
$version
);
$minphp
=
qa_version_to_float
(
$version
);
$thisphp
=
qa_version_to_float
(
phpversion
());
$thisphp
=
qa_version_to_float
(
phpversion
());
return
$minphp
&&
$thisphp
&&
(
$thisphp
<
$minphp
)
;
return
$minphp
&&
$thisphp
&&
$thisphp
<
$minphp
;
}
}
// Initialization functions called above
// Initialization functions called above
/**
/**
* Set up and verify the PHP environment for Q2A, including unregistering globals if necessary
* Set up and verify the PHP environment for Q2A, including unregistering globals if necessary
*/
*/
function
qa_initialize_php
()
function
qa_initialize_php
()
{
{
if
(
qa_php_version_below
(
'5.1.6'
))
if
(
qa_php_version_below
(
'5.1.6'
))
qa_fatal_error
(
'Q2A requires PHP 5.1.6 or later'
);
qa_fatal_error
(
'Q2A requires PHP 5.1.6 or later'
);
...
@@ -148,90 +135,95 @@
...
@@ -148,90 +135,95 @@
@
date_default_timezone_set
(
@
date_default_timezone_get
());
// prevent PHP notices where default timezone not set
@
date_default_timezone_set
(
@
date_default_timezone_get
());
// prevent PHP notices where default timezone not set
if
(
ini_get
(
'register_globals'
))
{
if
(
ini_get
(
'register_globals'
))
{
$checkarrays
=
array
(
'_ENV'
,
'_GET'
,
'_POST'
,
'_COOKIE'
,
'_SERVER'
,
'_FILES'
,
'_REQUEST'
,
'_SESSION'
);
// unregister globals if they're registered
$checkarrays
=
array
(
'_ENV'
,
'_GET'
,
'_POST'
,
'_COOKIE'
,
'_SERVER'
,
'_FILES'
,
'_REQUEST'
,
'_SESSION'
);
// unregister globals if they're registered
$keyprotect
=
array_flip
(
array_merge
(
$checkarrays
,
array
(
'GLOBALS'
)));
$keyprotect
=
array_flip
(
array_merge
(
$checkarrays
,
array
(
'GLOBALS'
)));
foreach
(
$checkarrays
as
$checkarray
)
foreach
(
$checkarrays
as
$checkarray
)
{
if
(
isset
(
${$checkarray}
)
&&
is_array
(
${$checkarray}
)
)
if
(
isset
(
${$checkarray}
)
&&
is_array
(
${$checkarray}
))
{
foreach
(
${$checkarray}
as
$checkkey
=>
$checkvalue
)
foreach
(
${$checkarray}
as
$checkkey
=>
$checkvalue
)
{
if
(
isset
(
$keyprotect
[
$checkkey
]))
if
(
isset
(
$keyprotect
[
$checkkey
]))
{
qa_fatal_error
(
'My superglobals are not for overriding'
);
qa_fatal_error
(
'My superglobals are not for overriding'
);
else
}
else
{
unset
(
$GLOBALS
[
$checkkey
]);
unset
(
$GLOBALS
[
$checkkey
]);
}
}
}
}
}
}
}
}
/**
/**
* First stage of setting up Q2A constants, before (if necessary) loading WordPress or Joomla! integration
* First stage of setting up Q2A constants, before (if necessary) loading WordPress or Joomla! integration
*/
*/
function
qa_initialize_constants_1
()
function
qa_initialize_constants_1
()
{
{
global
$qa_request_map
;
global
$qa_request_map
;
define
(
'QA_CATEGORY_DEPTH'
,
4
);
// you can't change this number!
define
(
'QA_CATEGORY_DEPTH'
,
4
);
// you can't change this number!
if
(
!
defined
(
'QA_BASE_DIR'
))
if
(
!
defined
(
'QA_BASE_DIR'
))
define
(
'QA_BASE_DIR'
,
dirname
(
dirname
(
__FILE__
))
.
'/'
);
// try out best if not set in index.php or qa-index.php - won't work with symbolic links
define
(
'QA_BASE_DIR'
,
dirname
(
dirname
(
__FILE__
))
.
'/'
);
// try out best if not set in index.php or qa-index.php - won't work with symbolic links
define
(
'QA_EXTERNAL_DIR'
,
QA_BASE_DIR
.
'qa-external/'
);
define
(
'QA_EXTERNAL_DIR'
,
QA_BASE_DIR
.
'qa-external/'
);
define
(
'QA_INCLUDE_DIR'
,
QA_BASE_DIR
.
'qa-include/'
);
define
(
'QA_INCLUDE_DIR'
,
QA_BASE_DIR
.
'qa-include/'
);
define
(
'QA_LANG_DIR'
,
QA_BASE_DIR
.
'qa-lang/'
);
define
(
'QA_LANG_DIR'
,
QA_BASE_DIR
.
'qa-lang/'
);
define
(
'QA_THEME_DIR'
,
QA_BASE_DIR
.
'qa-theme/'
);
define
(
'QA_THEME_DIR'
,
QA_BASE_DIR
.
'qa-theme/'
);
define
(
'QA_PLUGIN_DIR'
,
QA_BASE_DIR
.
'qa-plugin/'
);
define
(
'QA_PLUGIN_DIR'
,
QA_BASE_DIR
.
'qa-plugin/'
);
if
(
!
file_exists
(
QA_BASE_DIR
.
'qa-config.php'
))
if
(
!
file_exists
(
QA_BASE_DIR
.
'qa-config.php'
))
qa_fatal_error
(
'The config file could not be found. Please read the instructions in qa-config-example.php.'
);
qa_fatal_error
(
'The config file could not be found. Please read the instructions in qa-config-example.php.'
);
require_once
QA_BASE_DIR
.
'qa-config.php'
;
require_once
QA_BASE_DIR
.
'qa-config.php'
;
$qa_request_map
=
isset
(
$QA_CONST_PATH_MAP
)
&&
is_array
(
$QA_CONST_PATH_MAP
)
?
$QA_CONST_PATH_MAP
:
array
();
$qa_request_map
=
isset
(
$QA_CONST_PATH_MAP
)
&&
is_array
(
$QA_CONST_PATH_MAP
)
?
$QA_CONST_PATH_MAP
:
array
();
if
(
defined
(
'QA_WORDPRESS_INTEGRATE_PATH'
)
&&
strlen
(
QA_WORDPRESS_INTEGRATE_PATH
))
{
if
(
defined
(
'QA_WORDPRESS_INTEGRATE_PATH'
)
&&
strlen
(
QA_WORDPRESS_INTEGRATE_PATH
))
{
define
(
'QA_FINAL_WORDPRESS_INTEGRATE_PATH'
,
QA_WORDPRESS_INTEGRATE_PATH
.
((
substr
(
QA_WORDPRESS_INTEGRATE_PATH
,
-
1
)
==
'/'
)
?
''
:
'/'
));
define
(
'QA_FINAL_WORDPRESS_INTEGRATE_PATH'
,
QA_WORDPRESS_INTEGRATE_PATH
.
((
substr
(
QA_WORDPRESS_INTEGRATE_PATH
,
-
1
)
==
'/'
)
?
''
:
'/'
));
define
(
'QA_WORDPRESS_LOAD_FILE'
,
QA_FINAL_WORDPRESS_INTEGRATE_PATH
.
'wp-load.php'
);
define
(
'QA_WORDPRESS_LOAD_FILE'
,
QA_FINAL_WORDPRESS_INTEGRATE_PATH
.
'wp-load.php'
);
if
(
!
is_readable
(
QA_WORDPRESS_LOAD_FILE
))
if
(
!
is_readable
(
QA_WORDPRESS_LOAD_FILE
))
{
qa_fatal_error
(
'Could not find wp-load.php file for WordPress integration - please check QA_WORDPRESS_INTEGRATE_PATH in qa-config.php'
);
qa_fatal_error
(
'Could not find wp-load.php file for WordPress integration - please check QA_WORDPRESS_INTEGRATE_PATH in qa-config.php'
);
}
}
elseif
(
defined
(
'QA_JOOMLA_INTEGRATE_PATH'
)
&&
strlen
(
QA_JOOMLA_INTEGRATE_PATH
))
{
}
elseif
(
defined
(
'QA_JOOMLA_INTEGRATE_PATH'
)
&&
strlen
(
QA_JOOMLA_INTEGRATE_PATH
))
{
define
(
'QA_FINAL_JOOMLA_INTEGRATE_PATH'
,
QA_JOOMLA_INTEGRATE_PATH
.
((
substr
(
QA_JOOMLA_INTEGRATE_PATH
,
-
1
)
==
'/'
)
?
''
:
'/'
));
define
(
'QA_FINAL_JOOMLA_INTEGRATE_PATH'
,
QA_JOOMLA_INTEGRATE_PATH
.
((
substr
(
QA_JOOMLA_INTEGRATE_PATH
,
-
1
)
==
'/'
)
?
''
:
'/'
));
define
(
'QA_JOOMLA_LOAD_FILE'
,
QA_FINAL_JOOMLA_INTEGRATE_PATH
.
'configuration.php'
);
define
(
'QA_JOOMLA_LOAD_FILE'
,
QA_FINAL_JOOMLA_INTEGRATE_PATH
.
'configuration.php'
);
if
(
!
is_readable
(
QA_JOOMLA_LOAD_FILE
))
if
(
!
is_readable
(
QA_JOOMLA_LOAD_FILE
))
{
qa_fatal_error
(
'Could not find configuration.php file for Joomla integration - please check QA_JOOMLA_INTEGRATE_PATH in qa-config.php'
);
qa_fatal_error
(
'Could not find configuration.php file for Joomla integration - please check QA_JOOMLA_INTEGRATE_PATH in qa-config.php'
);
}
}
}
// Polyfills
// Polyfills
// password_hash compatibility for 5.3-5.4
// password_hash compatibility for 5.3-5.4
define
(
'QA_PASSWORD_HASH'
,
!
qa_php_version_below
(
'5.3.7'
));
define
(
'QA_PASSWORD_HASH'
,
!
qa_php_version_below
(
'5.3.7'
));
if
(
QA_PASSWORD_HASH
)
{
if
(
QA_PASSWORD_HASH
)
{
require_once
QA_INCLUDE_DIR
.
'vendor/password_compat.php'
;
require_once
QA_INCLUDE_DIR
.
'vendor/password_compat.php'
;
}
}
// http://php.net/manual/en/function.hash-equals.php#115635
// http://php.net/manual/en/function.hash-equals.php#115635
if
(
!
function_exists
(
'hash_equals'
))
{
if
(
!
function_exists
(
'hash_equals'
))
{
function
hash_equals
(
$str1
,
$str2
)
{
function
hash_equals
(
$str1
,
$str2
)
if
(
strlen
(
$str1
)
!=
strlen
(
$str2
))
{
{
if
(
strlen
(
$str1
)
!=
strlen
(
$str2
))
{
return
false
;
return
false
;
}
else
{
}
else
{
$res
=
$str1
^
$str2
;
$res
=
$str1
^
$str2
;
$ret
=
0
;
$ret
=
0
;
for
(
$i
=
strlen
(
$res
)
-
1
;
$i
>=
0
;
$i
--
)
$ret
|=
ord
(
$res
[
$i
]);
for
(
$i
=
strlen
(
$res
)
-
1
;
$i
>=
0
;
$i
--
)
$ret
|=
ord
(
$res
[
$i
]);
return
!
$ret
;
return
!
$ret
;
}
}
}
}
}
}
}
}
/**
/**
* Second stage of setting up Q2A constants, after (if necessary) loading WordPress or Joomla! integration
* Second stage of setting up Q2A constants, after (if necessary) loading WordPress or Joomla! integration
*/
*/
function
qa_initialize_constants_2
()
function
qa_initialize_constants_2
()
{
{
// Default values if not set in qa-config.php
// Default values if not set in qa-config.php
@
define
(
'QA_COOKIE_DOMAIN'
,
''
);
@
define
(
'QA_COOKIE_DOMAIN'
,
''
);
...
@@ -268,20 +260,20 @@
...
@@ -268,20 +260,20 @@
{
{
if
(
is_array
(
$param
))
{
//
if
(
is_array
(
$param
))
{
//
foreach
(
$param
as
$key
=>
$value
)
foreach
(
$param
as
$key
=>
$value
)
$param
[
$key
]
=
qa_undo_wordpress_quoting
(
$value
,
$isget
);
$param
[
$key
]
=
qa_undo_wordpress_quoting
(
$value
,
$isget
);
}
else
{
}
else
{
$param
=
stripslashes
(
$param
);
$param
=
stripslashes
(
$param
);
if
(
$isget
)
if
(
$isget
)
$param
=
strtr
(
$param
,
array
(
'\\\''
=>
'\''
,
'\"'
=>
'"'
));
// also compensate for WordPress's .htaccess file
$param
=
strtr
(
$param
,
array
(
'\\\''
=>
'\''
,
'\"'
=>
'"'
));
// also compensate for WordPress's .htaccess file
}
}
return
$param
;
return
$param
;
}
}
$_GET
=
qa_undo_wordpress_quoting
(
$_GET
,
true
);
$_GET
=
qa_undo_wordpress_quoting
(
$_GET
,
true
);
$_POST
=
qa_undo_wordpress_quoting
(
$_POST
,
false
);
$_POST
=
qa_undo_wordpress_quoting
(
$_POST
,
false
);
$_SERVER
[
'PHP_SELF'
]
=
stripslashes
(
$_SERVER
[
'PHP_SELF'
]);
$_SERVER
[
'PHP_SELF'
]
=
stripslashes
(
$_SERVER
[
'PHP_SELF'
]);
}
elseif
(
defined
(
'QA_FINAL_JOOMLA_INTEGRATE_PATH'
))
{
}
elseif
(
defined
(
'QA_FINAL_JOOMLA_INTEGRATE_PATH'
))
{
// More for Joomla integration
// More for Joomla integration
...
@@ -312,32 +304,32 @@
...
@@ -312,32 +304,32 @@
define
(
'QA_URL_FORMAT_SAFEST'
,
5
);
// http://...../index.php?qa=123&qa_1=why-is-the-sky-blue
define
(
'QA_URL_FORMAT_SAFEST'
,
5
);
// http://...../index.php?qa=123&qa_1=why-is-the-sky-blue
define
(
'QA_URL_TEST_STRING'
,
'$&-_~#%\\@^*()][`\';=:|".{},!<>?# π§½Жש'
);
// tests escaping, spaces, quote slashing and unicode - but not + and /
define
(
'QA_URL_TEST_STRING'
,
'$&-_~#%\\@^*()][`\';=:|".{},!<>?# π§½Жש'
);
// tests escaping, spaces, quote slashing and unicode - but not + and /
}
}
/**
/**
* Gets everything ready to start using modules, layers and overrides
* Gets everything ready to start using modules, layers and overrides
*/
*/
function
qa_initialize_modularity
()
function
qa_initialize_modularity
()
{
{
global
$qa_modules
,
$qa_layers
,
$qa_override_files
,
$qa_override_files_temp
,
$qa_overrides
,
$qa_direct
;
global
$qa_modules
,
$qa_layers
,
$qa_override_files
,
$qa_override_files_temp
,
$qa_overrides
,
$qa_direct
;
$qa_modules
=
array
();
$qa_modules
=
array
();
$qa_layers
=
array
();
$qa_layers
=
array
();
$qa_override_files
=
array
();
$qa_override_files
=
array
();
$qa_override_files_temp
=
array
();
$qa_override_files_temp
=
array
();
$qa_overrides
=
array
();
$qa_overrides
=
array
();
$qa_direct
=
array
();
$qa_direct
=
array
();
}
}
/**
/**
* Set up output buffering. Use gzip compression if option set and it's not an admin page (since some of these contain lengthy processes).
* Set up output buffering. Use gzip compression if option set and it's not an admin page (since some of these contain lengthy processes).
* @param $request
* @param $request
* @return bool whether buffering was used
* @return bool whether buffering was used
*/
*/
function
qa_initialize_buffering
(
$request
=
''
)
function
qa_initialize_buffering
(
$request
=
''
)
{
{
if
(
headers_sent
())
{
if
(
headers_sent
())
{
return
false
;
return
false
;
}
}
...
@@ -345,14 +337,14 @@
...
@@ -345,14 +337,14 @@
$useGzip
=
QA_HTML_COMPRESSION
&&
substr
(
$request
,
0
,
6
)
!==
'admin/'
&&
extension_loaded
(
'zlib'
);
$useGzip
=
QA_HTML_COMPRESSION
&&
substr
(
$request
,
0
,
6
)
!==
'admin/'
&&
extension_loaded
(
'zlib'
);
ob_start
(
$useGzip
?
'ob_gzhandler'
:
null
);
ob_start
(
$useGzip
?
'ob_gzhandler'
:
null
);
return
true
;
return
true
;
}
}
/**
/**
* Register all modules that come as part of the Q2A core (as opposed to plugins)
* Register all modules that come as part of the Q2A core (as opposed to plugins)
*/
*/
function
qa_register_core_modules
()
function
qa_register_core_modules
()
{
{
qa_register_module
(
'filter'
,
'plugins/qa-filter-basic.php'
,
'qa_filter_basic'
,
''
);
qa_register_module
(
'filter'
,
'plugins/qa-filter-basic.php'
,
'qa_filter_basic'
,
''
);
qa_register_module
(
'editor'
,
'plugins/qa-editor-basic.php'
,
'qa_editor_basic'
,
''
);
qa_register_module
(
'editor'
,
'plugins/qa-editor-basic.php'
,
'qa_editor_basic'
,
''
);
qa_register_module
(
'viewer'
,
'plugins/qa-viewer-basic.php'
,
'qa_viewer_basic'
,
''
);
qa_register_module
(
'viewer'
,
'plugins/qa-viewer-basic.php'
,
'qa_viewer_basic'
,
''
);
...
@@ -364,18 +356,36 @@
...
@@ -364,18 +356,36 @@
qa_register_module
(
'widget'
,
'plugins/qa-widget-ask-box.php'
,
'qa_ask_box'
,
'Ask Box'
);
qa_register_module
(
'widget'
,
'plugins/qa-widget-ask-box.php'
,
'qa_ask_box'
,
'Ask Box'
);
qa_register_module
(
'widget'
,
'plugins/qa-widget-related-qs.php'
,
'qa_related_qs'
,
'Related Questions'
);
qa_register_module
(
'widget'
,
'plugins/qa-widget-related-qs.php'
,
'qa_related_qs'
,
'Related Questions'
);
qa_register_module
(
'widget'
,
'plugins/qa-widget-category-list.php'
,
'qa_category_list'
,
'Categories'
);
qa_register_module
(
'widget'
,
'plugins/qa-widget-category-list.php'
,
'qa_category_list'
,
'Categories'
);
}
}
/**
/**
* Load all plugins. They are split into two groups: plugins loaded before database is available, and those loaded afterward.
*/
function
qa_initialize_plugins
()
{
$pluginManager
=
new
Q2A_Plugin_PluginManager
();
$pluginManager
->
readAllPluginMetadatas
();
$pluginManager
->
loadPluginsBeforeDbInit
();
qa_load_override_files
();
qa_db_allow_connect
();
$pluginManager
->
loadPluginsAfterDbInit
();
qa_load_override_files
();
}
/**
* Retrieve metadata information from the $contents of a qa-theme.php or qa-plugin.php file, specified by $type ('Plugin' or 'Theme').
* Retrieve metadata information from the $contents of a qa-theme.php or qa-plugin.php file, specified by $type ('Plugin' or 'Theme').
* If $versiononly is true, only min version metadata is parsed.
* If $versiononly is true, only min version metadata is parsed.
* Name, Description, Min Q2A & Min PHP are not currently used by themes.
* Name, Description, Min Q2A & Min PHP are not currently used by themes.
*
*
* @deprecated Deprecated from 1.7; Q2A_Util_Metadata class and metadata.json files should be used instead
* @deprecated Deprecated from 1.7; Q2A_Util_Metadata class and metadata.json files should be used instead
*/
*/
function
qa_addon_metadata
(
$contents
,
$type
,
$versiononly
=
false
)
function
qa_addon_metadata
(
$contents
,
$type
,
$versiononly
=
false
)
{
{
$fields
=
array
(
$fields
=
array
(
'min_q2a'
=>
'Minimum Question2Answer Version'
,
'min_q2a'
=>
'Minimum Question2Answer Version'
,
'min_php'
=>
'Minimum PHP Version'
,
'min_php'
=>
'Minimum PHP Version'
,
...
@@ -398,52 +408,54 @@
...
@@ -398,52 +408,54 @@
foreach
(
$fields
as
$key
=>
$field
)
{
foreach
(
$fields
as
$key
=>
$field
)
{
// prepend 'Theme'/'Plugin' and search for key data
// prepend 'Theme'/'Plugin' and search for key data
$fieldregex
=
str_replace
(
' '
,
'[ \t]*'
,
preg_quote
(
"
$type
$field
"
,
'/'
));
$fieldregex
=
str_replace
(
' '
,
'[ \t]*'
,
preg_quote
(
"
$type
$field
"
,
'/'
));
if
(
preg_match
(
'/'
.
$fieldregex
.
':[ \t]*([^\n\f]*)[\n\f]/i'
,
$contents
,
$matches
))
if
(
preg_match
(
'/'
.
$fieldregex
.
':[ \t]*([^\n\f]*)[\n\f]/i'
,
$contents
,
$matches
))
$metadata
[
$key
]
=
trim
(
$matches
[
1
]);
$metadata
[
$key
]
=
trim
(
$matches
[
1
]);
}
}
return
$metadata
;
return
$metadata
;
}
}
/**
/**
* Apply all the function overrides in override files that have been registered by plugins
* Apply all the function overrides in override files that have been registered by plugins
*/
*/
function
qa_load_override_files
()
function
qa_load_override_files
()
{
{
global
$qa_override_files
,
$qa_override_files_temp
,
$qa_overrides
;
global
$qa_override_files
,
$qa_override_files_temp
,
$qa_overrides
;
$functionindex
=
array
();
$functionindex
=
array
();
foreach
(
$qa_override_files_temp
as
$override
)
{
foreach
(
$qa_override_files_temp
as
$override
)
{
$qa_override_files
[]
=
$override
;
$qa_override_files
[]
=
$override
;
$filename
=
$override
[
'directory'
]
.
$override
[
'include'
];
$filename
=
$override
[
'directory'
]
.
$override
[
'include'
];
$functionsphp
=
file_get_contents
(
$filename
);
$functionsphp
=
file_get_contents
(
$filename
);
preg_match_all
(
'/\Wfunction\s+(qa_[a-z_]+)\s*\(/im'
,
$functionsphp
,
$rawmatches
,
PREG_PATTERN_ORDER
|
PREG_OFFSET_CAPTURE
);
preg_match_all
(
'/\Wfunction\s+(qa_[a-z_]+)\s*\(/im'
,
$functionsphp
,
$rawmatches
,
PREG_PATTERN_ORDER
|
PREG_OFFSET_CAPTURE
);
$reversematches
=
array_reverse
(
$rawmatches
[
1
],
true
);
// reverse so offsets remain correct as we step through
$reversematches
=
array_reverse
(
$rawmatches
[
1
],
true
);
// reverse so offsets remain correct as we step through
$postreplace
=
array
();
$postreplace
=
array
();
$suffix
=
'_in_'
.
preg_replace
(
'/[^A-Za-z0-9_]+/'
,
'_'
,
basename
(
$override
[
'include'
]));
// include file name in defined function names to make debugging easier if there is an error
// include file name in defined function names to make debugging easier if there is an error
$suffix
=
'_in_'
.
preg_replace
(
'/[^A-Za-z0-9_]+/'
,
'_'
,
basename
(
$override
[
'include'
]));
foreach
(
$reversematches
as
$rawmatch
)
{
foreach
(
$reversematches
as
$rawmatch
)
{
$function
=
strtolower
(
$rawmatch
[
0
]);
$function
=
strtolower
(
$rawmatch
[
0
]);
$position
=
$rawmatch
[
1
];
$position
=
$rawmatch
[
1
];
if
(
isset
(
$qa_overrides
[
$function
]))
if
(
isset
(
$qa_overrides
[
$function
]))
$postreplace
[
$function
.
'_base'
]
=
$qa_overrides
[
$function
];
$postreplace
[
$function
.
'_base'
]
=
$qa_overrides
[
$function
];
$newname
=
$function
.
'_override_'
.
(
@++
$functionindex
[
$function
])
.
$suffix
;
$newname
=
$function
.
'_override_'
.
(
@++
$functionindex
[
$function
])
.
$suffix
;
$functionsphp
=
substr_replace
(
$functionsphp
,
$newname
,
$position
,
strlen
(
$function
));
$functionsphp
=
substr_replace
(
$functionsphp
,
$newname
,
$position
,
strlen
(
$function
));
$qa_overrides
[
$function
]
=
$newname
;
$qa_overrides
[
$function
]
=
$newname
;
}
}
foreach
(
$postreplace
as
$oldname
=>
$newname
)
foreach
(
$postreplace
as
$oldname
=>
$newname
)
{
if
(
preg_match_all
(
'/\W('
.
preg_quote
(
$oldname
)
.
')\s*\(/im'
,
$functionsphp
,
$matches
,
PREG_PATTERN_ORDER
|
PREG_OFFSET_CAPTURE
))
{
if
(
preg_match_all
(
'/\W('
.
preg_quote
(
$oldname
)
.
')\s*\(/im'
,
$functionsphp
,
$matches
,
PREG_PATTERN_ORDER
|
PREG_OFFSET_CAPTURE
))
{
$searchmatches
=
array_reverse
(
$matches
[
1
]);
$searchmatches
=
array_reverse
(
$matches
[
1
]);
foreach
(
$searchmatches
as
$searchmatch
)
foreach
(
$searchmatches
as
$searchmatch
)
{
$functionsphp
=
substr_replace
(
$functionsphp
,
$newname
,
$searchmatch
[
1
],
strlen
(
$searchmatch
[
0
]));
$functionsphp
=
substr_replace
(
$functionsphp
,
$newname
,
$searchmatch
[
1
],
strlen
(
$searchmatch
[
0
]));
}
}
}
}
// echo '<pre style="text-align:left;">'.htmlspecialchars($functionsphp).'</pre>'; // to debug munged code
// echo '<pre style="text-align:left;">'.htmlspecialchars($functionsphp).'</pre>'; // to debug munged code
...
@@ -452,187 +464,200 @@
...
@@ -452,187 +464,200 @@
}
}
$qa_override_files_temp
=
array
();
$qa_override_files_temp
=
array
();
}
}
// Functions for registering different varieties of Q2A modularity
// Functions for registering different varieties of Q2A modularity
/**
/**
* Register a module of $type named $name, whose class named $class is defined in file $include (or null if no include necessary)
* Register a module of $type named $name, whose class named $class is defined in file $include (or null if no include necessary)
* If this module comes from a plugin, pass in the local plugin $directory and the $urltoroot relative url for that directory
* If this module comes from a plugin, pass in the local plugin $directory and the $urltoroot relative url for that directory
*/
*/
function
qa_register_module
(
$type
,
$include
,
$class
,
$name
,
$directory
=
QA_INCLUDE_DIR
,
$urltoroot
=
null
)
function
qa_register_module
(
$type
,
$include
,
$class
,
$name
,
$directory
=
QA_INCLUDE_DIR
,
$urltoroot
=
null
)
{
{
global
$qa_modules
;
global
$qa_modules
;
$previous
=
@
$qa_modules
[
$type
][
$name
];
$previous
=
@
$qa_modules
[
$type
][
$name
];
if
(
isset
(
$previous
))
if
(
isset
(
$previous
))
{
qa_fatal_error
(
'A '
.
$type
.
' module named '
.
$name
.
' already exists. Please check there are no duplicate plugins. '
.
qa_fatal_error
(
'A '
.
$type
.
' module named '
.
$name
.
' already exists. Please check there are no duplicate plugins. '
.
"
\n\n
Module 1: "
.
$previous
[
'directory'
]
.
$previous
[
'include'
]
.
"
\n
Module 2: "
.
$directory
.
$include
);
"
\n\n
Module 1: "
.
$previous
[
'directory'
]
.
$previous
[
'include'
]
.
"
\n
Module 2: "
.
$directory
.
$include
);
}
$qa_modules
[
$type
][
$name
]
=
array
(
$qa_modules
[
$type
][
$name
]
=
array
(
'directory'
=>
$directory
,
'directory'
=>
$directory
,
'urltoroot'
=>
$urltoroot
,
'urltoroot'
=>
$urltoroot
,
'include'
=>
$include
,
'include'
=>
$include
,
'class'
=>
$class
,
'class'
=>
$class
,
);
);
}
}
/**
/**
* Register a layer named $name, defined in file $include. If this layer comes from a plugin (as all currently do),
* Register a layer named $name, defined in file $include. If this layer comes from a plugin (as all currently do),
* pass in the local plugin $directory and the $urltoroot relative url for that directory
* pass in the local plugin $directory and the $urltoroot relative url for that directory
*/
*/
function
qa_register_layer
(
$include
,
$name
,
$directory
=
QA_INCLUDE_DIR
,
$urltoroot
=
null
)
function
qa_register_layer
(
$include
,
$name
,
$directory
=
QA_INCLUDE_DIR
,
$urltoroot
=
null
)
{
{
global
$qa_layers
;
global
$qa_layers
;
$previous
=
@
$qa_layers
[
$name
];
$previous
=
@
$qa_layers
[
$name
];
if
(
isset
(
$previous
))
if
(
isset
(
$previous
))
{
qa_fatal_error
(
'A layer named '
.
$name
.
' already exists. Please check there are no duplicate plugins. '
.
qa_fatal_error
(
'A layer named '
.
$name
.
' already exists. Please check there are no duplicate plugins. '
.
"
\n\n
Layer 1: "
.
$previous
[
'directory'
]
.
$previous
[
'include'
]
.
"
\n
Layer 2: "
.
$directory
.
$include
);
"
\n\n
Layer 1: "
.
$previous
[
'directory'
]
.
$previous
[
'include'
]
.
"
\n
Layer 2: "
.
$directory
.
$include
);
}
$qa_layers
[
$name
]
=
array
(
$qa_layers
[
$name
]
=
array
(
'directory'
=>
$directory
,
'directory'
=>
$directory
,
'urltoroot'
=>
$urltoroot
,
'urltoroot'
=>
$urltoroot
,
'include'
=>
$include
,
'include'
=>
$include
,
);
);
}
}
/**
/**
* Register a file $include containing override functions. If this file comes from a plugin (as all currently do),
* Register a file $include containing override functions. If this file comes from a plugin (as all currently do),
* pass in the local plugin $directory and the $urltoroot relative url for that directory
* pass in the local plugin $directory and the $urltoroot relative url for that directory
*/
*/
function
qa_register_overrides
(
$include
,
$directory
=
QA_INCLUDE_DIR
,
$urltoroot
=
null
)
function
qa_register_overrides
(
$include
,
$directory
=
QA_INCLUDE_DIR
,
$urltoroot
=
null
)
{
{
global
$qa_override_files_temp
;
global
$qa_override_files_temp
;
$qa_override_files_temp
[]
=
array
(
$qa_override_files_temp
[]
=
array
(
'directory'
=>
$directory
,
'directory'
=>
$directory
,
'urltoroot'
=>
$urltoroot
,
'urltoroot'
=>
$urltoroot
,
'include'
=>
$include
'include'
=>
$include
,
);
);
}
}
/**
/**
* Register a set of language phrases, which should be accessed by the prefix $name/ in the qa_lang_*() functions.
* Register a set of language phrases, which should be accessed by the prefix $name/ in the qa_lang_*() functions.
* Pass in the $pattern representing the PHP files that define these phrases, where * in the pattern is replaced with
* Pass in the $pattern representing the PHP files that define these phrases, where * in the pattern is replaced with
* the language code (e.g. 'fr') and/or 'default'. These files should be formatted like Q2A's qa-lang-*.php files.
* the language code (e.g. 'fr') and/or 'default'. These files should be formatted like Q2A's qa-lang-*.php files.
*/
*/
function
qa_register_phrases
(
$pattern
,
$name
)
function
qa_register_phrases
(
$pattern
,
$name
)
{
{
global
$qa_lang_file_pattern
;
global
$qa_lang_file_pattern
;
if
(
file_exists
(
QA_INCLUDE_DIR
.
'lang/qa-lang-'
.
$name
.
'.php'
))
if
(
file_exists
(
QA_INCLUDE_DIR
.
'lang/qa-lang-'
.
$name
.
'.php'
))
{
qa_fatal_error
(
'The name "'
.
$name
.
'" for phrases is reserved and cannot be used by plugins.'
.
"
\n\n
Phrases: "
.
$pattern
);
qa_fatal_error
(
'The name "'
.
$name
.
'" for phrases is reserved and cannot be used by plugins.'
.
"
\n\n
Phrases: "
.
$pattern
);
}
if
(
isset
(
$qa_lang_file_pattern
[
$name
]))
qa_fatal_error
(
'A set of phrases named '
.
$name
.
' already exists. Please check there are no duplicate plugins. '
.
"
\n\n
Phrases 1: "
.
$qa_lang_file_pattern
[
$name
]
.
"
\n
Phrases 2: "
.
$pattern
);
$qa_lang_file_pattern
[
$name
]
=
$pattern
;
if
(
isset
(
$qa_lang_file_pattern
[
$name
]))
{
qa_fatal_error
(
'A set of phrases named '
.
$name
.
' already exists. Please check there are no duplicate plugins. '
.
"
\n\n
Phrases 1: "
.
$qa_lang_file_pattern
[
$name
]
.
"
\n
Phrases 2: "
.
$pattern
);
}
}
$qa_lang_file_pattern
[
$name
]
=
$pattern
;
}
// Function for registering varieties of Q2A modularity, which are (only) called from qa-plugin.php files
// Function for registering varieties of Q2A modularity, which are (only) called from qa-plugin.php files
/**
/**
* Register a plugin module of $type named $name, whose class named $class is defined in file $include (or null if no include necessary)
* Register a plugin module of $type named $name, whose class named $class is defined in file $include (or null if no include necessary)
* This function relies on some global variable values and can only be called from a plugin's qa-plugin.php file
* This function relies on some global variable values and can only be called from a plugin's qa-plugin.php file
*/
*/
function
qa_register_plugin_module
(
$type
,
$include
,
$class
,
$name
)
function
qa_register_plugin_module
(
$type
,
$include
,
$class
,
$name
)
{
{
global
$qa_plugin_directory
,
$qa_plugin_urltoroot
;
global
$qa_plugin_directory
,
$qa_plugin_urltoroot
;
if
(
empty
(
$qa_plugin_directory
)
||
empty
(
$qa_plugin_urltoroot
))
if
(
empty
(
$qa_plugin_directory
)
||
empty
(
$qa_plugin_urltoroot
))
{
qa_fatal_error
(
'qa_register_plugin_module() can only be called from a plugin qa-plugin.php file'
);
qa_fatal_error
(
'qa_register_plugin_module() can only be called from a plugin qa-plugin.php file'
);
}
qa_register_module
(
$type
,
$include
,
$class
,
$name
,
$qa_plugin_directory
,
$qa_plugin_urltoroot
);
qa_register_module
(
$type
,
$include
,
$class
,
$name
,
$qa_plugin_directory
,
$qa_plugin_urltoroot
);
}
}
/**
/**
* Register a plugin layer named $name, defined in file $include. Can only be called from a plugin's qa-plugin.php file
* Register a plugin layer named $name, defined in file $include. Can only be called from a plugin's qa-plugin.php file
*/
*/
function
qa_register_plugin_layer
(
$include
,
$name
)
function
qa_register_plugin_layer
(
$include
,
$name
)
{
{
global
$qa_plugin_directory
,
$qa_plugin_urltoroot
;
global
$qa_plugin_directory
,
$qa_plugin_urltoroot
;
if
(
empty
(
$qa_plugin_directory
)
||
empty
(
$qa_plugin_urltoroot
))
if
(
empty
(
$qa_plugin_directory
)
||
empty
(
$qa_plugin_urltoroot
))
{
qa_fatal_error
(
'qa_register_plugin_layer() can only be called from a plugin qa-plugin.php file'
);
qa_fatal_error
(
'qa_register_plugin_layer() can only be called from a plugin qa-plugin.php file'
);
}
qa_register_layer
(
$include
,
$name
,
$qa_plugin_directory
,
$qa_plugin_urltoroot
);
qa_register_layer
(
$include
,
$name
,
$qa_plugin_directory
,
$qa_plugin_urltoroot
);
}
}
/**
/**
* Register a plugin file $include containing override functions. Can only be called from a plugin's qa-plugin.php file
* Register a plugin file $include containing override functions. Can only be called from a plugin's qa-plugin.php file
*/
*/
function
qa_register_plugin_overrides
(
$include
)
function
qa_register_plugin_overrides
(
$include
)
{
{
global
$qa_plugin_directory
,
$qa_plugin_urltoroot
;
global
$qa_plugin_directory
,
$qa_plugin_urltoroot
;
if
(
empty
(
$qa_plugin_directory
)
||
empty
(
$qa_plugin_urltoroot
))
if
(
empty
(
$qa_plugin_directory
)
||
empty
(
$qa_plugin_urltoroot
))
{
qa_fatal_error
(
'qa_register_plugin_overrides() can only be called from a plugin qa-plugin.php file'
);
qa_fatal_error
(
'qa_register_plugin_overrides() can only be called from a plugin qa-plugin.php file'
);
}
qa_register_overrides
(
$include
,
$qa_plugin_directory
,
$qa_plugin_urltoroot
);
qa_register_overrides
(
$include
,
$qa_plugin_directory
,
$qa_plugin_urltoroot
);
}
}
/**
/**
* Register a file name $pattern within a plugin directory containing language phrases accessed by the prefix $name
* Register a file name $pattern within a plugin directory containing language phrases accessed by the prefix $name
*/
*/
function
qa_register_plugin_phrases
(
$pattern
,
$name
)
function
qa_register_plugin_phrases
(
$pattern
,
$name
)
{
{
global
$qa_plugin_directory
,
$qa_plugin_urltoroot
;
global
$qa_plugin_directory
,
$qa_plugin_urltoroot
;
if
(
empty
(
$qa_plugin_directory
)
||
empty
(
$qa_plugin_urltoroot
))
if
(
empty
(
$qa_plugin_directory
)
||
empty
(
$qa_plugin_urltoroot
))
{
qa_fatal_error
(
'qa_register_plugin_phrases() can only be called from a plugin qa-plugin.php file'
);
qa_fatal_error
(
'qa_register_plugin_phrases() can only be called from a plugin qa-plugin.php file'
);
qa_register_phrases
(
$qa_plugin_directory
.
$pattern
,
$name
);
}
}
qa_register_phrases
(
$qa_plugin_directory
.
$pattern
,
$name
);
}
// Low-level functions used throughout Q2A
// Low-level functions used throughout Q2A
/**
/**
* Calls eval() on the PHP code in $eval which came from the file $filename. It supplements PHP's regular error reporting by
* Calls eval() on the PHP code in $eval which came from the file $filename. It supplements PHP's regular error reporting by
* displaying/logging (as appropriate) the original source filename, if an error occurred when evaluating the code.
* displaying/logging (as appropriate) the original source filename, if an error occurred when evaluating the code.
*/
*/
function
qa_eval_from_file
(
$eval
,
$filename
)
function
qa_eval_from_file
(
$eval
,
$filename
)
{
{
// could also use ini_set('error_append_string') but apparently it doesn't work for errors logged on disk
// could also use ini_set('error_append_string') but apparently it doesn't work for errors logged on disk
global
$php_errormsg
;
global
$php_errormsg
;
$oldtrackerrors
=
@
ini_set
(
'track_errors'
,
1
);
$oldtrackerrors
=
@
ini_set
(
'track_errors'
,
1
);
$php_errormsg
=
null
;
$php_errormsg
=
null
;
eval
(
'?'
.
'>'
.
$eval
);
eval
(
'?'
.
'>'
.
$eval
);
if
(
strlen
(
$php_errormsg
))
{
if
(
strlen
(
$php_errormsg
))
{
switch
(
strtolower
(
@
ini_get
(
'display_errors'
)))
{
switch
(
strtolower
(
@
ini_get
(
'display_errors'
)))
{
case
'on'
:
case
'1'
:
case
'yes'
:
case
'true'
:
case
'stdout'
:
case
'stderr'
:
case
'on'
:
echo
' of '
.
qa_html
(
$filename
)
.
"
\n
"
;
case
'1'
:
case
'yes'
:
case
'true'
:
case
'stdout'
:
case
'stderr'
:
echo
' of '
.
qa_html
(
$filename
)
.
"
\n
"
;
break
;
break
;
}
}
@
error_log
(
'PHP Question2Answer more info: '
.
$php_errormsg
.
" in eval()'d code from "
.
qa_html
(
$filename
));
@
error_log
(
'PHP Question2Answer more info: '
.
$php_errormsg
.
" in eval()'d code from "
.
qa_html
(
$filename
));
}
}
@
ini_set
(
'track_errors'
,
$oldtrackerrors
);
@
ini_set
(
'track_errors'
,
$oldtrackerrors
);
}
}
/**
/**
* Call $function with the arguments in the $args array (doesn't work with call-by-reference functions)
* Call $function with the arguments in the $args array (doesn't work with call-by-reference functions)
*/
*/
function
qa_call
(
$function
,
$args
)
function
qa_call
(
$function
,
$args
)
{
{
// call_user_func_array(...) is very slow, so we break out most common cases first
// call_user_func_array(...) is very slow, so we break out most common cases first
switch
(
count
(
$args
))
{
switch
(
count
(
$args
))
{
case
0
:
case
0
:
...
@@ -650,18 +675,18 @@
...
@@ -650,18 +675,18 @@
}
}
return
call_user_func_array
(
$function
,
$args
);
return
call_user_func_array
(
$function
,
$args
);
}
}
/**
/**
* Determines whether a function is to be overridden by a plugin. But if the function is being called with
* Determines whether a function is to be overridden by a plugin. But if the function is being called with
* the _base suffix, any override will be bypassed due to $qa_direct.
* the _base suffix, any override will be bypassed due to $qa_direct.
*
*
* @param string $function The function to override
* @param string $function The function to override
* @return string|null The name of the overriding function (of the form `qa_functionname_override_1_in_filename`)
* @return string|null The name of the overriding function (of the form `qa_functionname_override_1_in_filename`)
*/
*/
function
qa_to_override
(
$function
)
function
qa_to_override
(
$function
)
{
{
global
$qa_overrides
,
$qa_direct
;
global
$qa_overrides
,
$qa_direct
;
// handle most common case first
// handle most common case first
...
@@ -669,7 +694,7 @@
...
@@ -669,7 +694,7 @@
return
null
;
return
null
;
}
}
if
(
strpos
(
$function
,
'_override_'
)
!==
false
)
{
if
(
strpos
(
$function
,
'_override_'
)
!==
false
)
{
qa_fatal_error
(
'Override functions should not be calling qa_to_override()!'
);
qa_fatal_error
(
'Override functions should not be calling qa_to_override()!'
);
}
}
...
@@ -679,43 +704,46 @@
...
@@ -679,43 +704,46 @@
}
}
return
$qa_overrides
[
$function
];
return
$qa_overrides
[
$function
];
}
}
/**
/**
* Call the function which immediately overrides $function with the arguments in the $args array
* Call the function which immediately overrides $function with the arguments in the $args array
*/
*/
function
qa_call_override
(
$function
,
$args
)
function
qa_call_override
(
$function
,
$args
)
{
{
global
$qa_overrides
;
global
$qa_overrides
;
if
(
strpos
(
$function
,
'_override_'
)
!==
false
)
if
(
strpos
(
$function
,
'_override_'
)
!==
false
)
{
qa_fatal_error
(
'Override functions should not be calling qa_call_override()!'
);
qa_fatal_error
(
'Override functions should not be calling qa_call_override()!'
);
}
if
(
!
function_exists
(
$function
.
'_base'
))
// define the base function the first time that it's needed
if
(
!
function_exists
(
$function
.
'_base'
))
{
eval
(
'function '
.
$function
.
'_base() { global $qa_direct; $qa_direct[\''
.
$function
.
'\']=true; $args=func_get_args(); return qa_call(\''
.
$function
.
'\', $args); }'
);
// define the base function the first time that it's needed
eval
(
'function '
.
$function
.
'_base() { global $qa_direct; $qa_direct[\''
.
$function
.
'\']=true; $args=func_get_args(); return qa_call(\''
.
$function
.
'\', $args); }'
);
}
return
qa_call
(
$qa_overrides
[
$function
],
$args
);
return
qa_call
(
$qa_overrides
[
$function
],
$args
);
}
}
/**
/**
* Exit PHP immediately after reporting a shutdown with $reason to any installed process modules
* Exit PHP immediately after reporting a shutdown with $reason to any installed process modules
*/
*/
function
qa_exit
(
$reason
=
null
)
function
qa_exit
(
$reason
=
null
)
{
{
qa_report_process_stage
(
'shutdown'
,
$reason
);
qa_report_process_stage
(
'shutdown'
,
$reason
);
$code
=
$reason
===
'error'
?
1
:
0
;
$code
=
$reason
===
'error'
?
1
:
0
;
exit
(
$code
);
exit
(
$code
);
}
}
/**
/**
* Display $message in the browser, write it to server error log, and then stop abruptly
* Display $message in the browser, write it to server error log, and then stop abruptly
*/
*/
function
qa_fatal_error
(
$message
)
function
qa_fatal_error
(
$message
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
echo
'Question2Answer fatal error:<p style="color: red">'
.
qa_html
(
$message
,
true
)
.
'</p>'
;
echo
'Question2Answer fatal error:<p style="color: red">'
.
qa_html
(
$message
,
true
)
.
'</p>'
;
...
@@ -732,51 +760,51 @@
...
@@ -732,51 +760,51 @@
}
}
qa_exit
(
'error'
);
qa_exit
(
'error'
);
}
}
// Functions for listing, loading and getting info on modules
// Functions for listing, loading and getting info on modules
/**
/**
* Return an array with all registered modules' information
* Return an array with all registered modules' information
*/
*/
function
qa_list_modules_info
()
function
qa_list_modules_info
()
{
{
global
$qa_modules
;
global
$qa_modules
;
return
$qa_modules
;
return
$qa_modules
;
}
}
/**
/**
* Return an array of all the module types for which at least one module has been registered
* Return an array of all the module types for which at least one module has been registered
*/
*/
function
qa_list_module_types
()
function
qa_list_module_types
()
{
{
return
array_keys
(
qa_list_modules_info
());
return
array_keys
(
qa_list_modules_info
());
}
}
/**
/**
* Return a list of names of registered modules of $type
* Return a list of names of registered modules of $type
*/
*/
function
qa_list_modules
(
$type
)
function
qa_list_modules
(
$type
)
{
{
$modules
=
qa_list_modules_info
();
$modules
=
qa_list_modules_info
();
return
is_array
(
@
$modules
[
$type
])
?
array_keys
(
$modules
[
$type
])
:
array
();
return
is_array
(
@
$modules
[
$type
])
?
array_keys
(
$modules
[
$type
])
:
array
();
}
}
/**
/**
* Return an array containing information about the module of $type named $name
* Return an array containing information about the module of $type named $name
*/
*/
function
qa_get_module_info
(
$type
,
$name
)
function
qa_get_module_info
(
$type
,
$name
)
{
{
$modules
=
qa_list_modules_info
();
$modules
=
qa_list_modules_info
();
return
@
$modules
[
$type
][
$name
];
return
@
$modules
[
$type
][
$name
];
}
}
/**
/**
* Return an instantiated class for module of $type named $name, whose functions can be called, or null if it doesn't exist
* Return an instantiated class for module of $type named $name, whose functions can be called, or null if it doesn't exist
*/
*/
function
qa_load_module
(
$type
,
$name
)
function
qa_load_module
(
$type
,
$name
)
{
{
global
$qa_modules
;
global
$qa_modules
;
$module
=
@
$qa_modules
[
$type
][
$name
];
$module
=
@
$qa_modules
[
$type
][
$name
];
...
@@ -786,13 +814,13 @@
...
@@ -786,13 +814,13 @@
return
$module
[
'object'
];
return
$module
[
'object'
];
if
(
strlen
(
@
$module
[
'include'
]))
if
(
strlen
(
@
$module
[
'include'
]))
require_once
$module
[
'directory'
]
.
$module
[
'include'
];
require_once
$module
[
'directory'
]
.
$module
[
'include'
];
if
(
strlen
(
@
$module
[
'class'
]))
{
if
(
strlen
(
@
$module
[
'class'
]))
{
$object
=
new
$module
[
'class'
];
$object
=
new
$module
[
'class'
];
if
(
method_exists
(
$object
,
'load_module'
))
if
(
method_exists
(
$object
,
'load_module'
))
$object
->
load_module
(
$module
[
'directory'
],
qa_path_to_root
()
.
$module
[
'urltoroot'
],
$type
,
$name
);
$object
->
load_module
(
$module
[
'directory'
],
qa_path_to_root
()
.
$module
[
'urltoroot'
],
$type
,
$name
);
$qa_modules
[
$type
][
$name
][
'object'
]
=
$object
;
$qa_modules
[
$type
][
$name
][
'object'
]
=
$object
;
return
$object
;
return
$object
;
...
@@ -800,14 +828,14 @@
...
@@ -800,14 +828,14 @@
}
}
return
null
;
return
null
;
}
}
/**
/**
* Return an array of instantiated clases for modules which have defined $method
* Return an array of instantiated clases for modules which have defined $method
* (all modules are loaded but not included in the returned array)
* (all modules are loaded but not included in the returned array)
*/
*/
function
qa_load_all_modules_with
(
$method
)
function
qa_load_all_modules_with
(
$method
)
{
{
$modules
=
array
();
$modules
=
array
();
$regmodules
=
qa_list_modules_info
();
$regmodules
=
qa_list_modules_info
();
...
@@ -822,14 +850,14 @@
...
@@ -822,14 +850,14 @@
}
}
return
$modules
;
return
$modules
;
}
}
/**
/**
* Return an array of instantiated clases for modules of $type which have defined $method
* Return an array of instantiated clases for modules of $type which have defined $method
* (other modules of that type are also loaded but not included in the returned array)
* (other modules of that type are also loaded but not included in the returned array)
*/
*/
function
qa_load_modules_with
(
$type
,
$method
)
function
qa_load_modules_with
(
$type
,
$method
)
{
{
$modules
=
array
();
$modules
=
array
();
$trynames
=
qa_list_modules
(
$type
);
$trynames
=
qa_list_modules
(
$type
);
...
@@ -842,45 +870,45 @@
...
@@ -842,45 +870,45 @@
}
}
return
$modules
;
return
$modules
;
}
}
// HTML and Javascript escaping and sanitization
// HTML and Javascript escaping and sanitization
/**
/**
* Return HTML representation of $string, work well with blocks of text if $multiline is true
* Return HTML representation of $string, work well with blocks of text if $multiline is true
*/
*/
function
qa_html
(
$string
,
$multiline
=
false
)
function
qa_html
(
$string
,
$multiline
=
false
)
{
{
$html
=
htmlspecialchars
((
string
)
$string
);
$html
=
htmlspecialchars
((
string
)
$string
);
if
(
$multiline
)
{
if
(
$multiline
)
{
$html
=
preg_replace
(
'/\r\n?/'
,
"
\n
"
,
$html
);
$html
=
preg_replace
(
'/\r\n?/'
,
"
\n
"
,
$html
);
$html
=
preg_replace
(
'/(?<=\s) /'
,
' '
,
$html
);
$html
=
preg_replace
(
'/(?<=\s) /'
,
' '
,
$html
);
$html
=
str_replace
(
"
\t
"
,
' '
,
$html
);
$html
=
str_replace
(
"
\t
"
,
' '
,
$html
);
$html
=
nl2br
(
$html
);
$html
=
nl2br
(
$html
);
}
}
return
$html
;
return
$html
;
}
}
/**
/**
* Return $html after ensuring it is safe, i.e. removing Javascripts and the like - uses htmLawed library
* Return $html after ensuring it is safe, i.e. removing Javascripts and the like - uses htmLawed library
* Links open in a new window if $linksnewwindow is true. Set $storage to true if sanitization is for
* Links open in a new window if $linksnewwindow is true. Set $storage to true if sanitization is for
* storing in the database, rather than immediate display to user - some think this should be less strict.
* storing in the database, rather than immediate display to user - some think this should be less strict.
*/
*/
function
qa_sanitize_html
(
$html
,
$linksnewwindow
=
false
,
$storage
=
false
)
function
qa_sanitize_html
(
$html
,
$linksnewwindow
=
false
,
$storage
=
false
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
require_once
'vendor/htmLawed.php'
;
require_once
'vendor/htmLawed.php'
;
global
$qa_sanitize_html_newwindow
;
global
$qa_sanitize_html_newwindow
;
$qa_sanitize_html_newwindow
=
$linksnewwindow
;
$qa_sanitize_html_newwindow
=
$linksnewwindow
;
$safe
=
htmLawed
(
$html
,
array
(
$safe
=
htmLawed
(
$html
,
array
(
'safe'
=>
1
,
'safe'
=>
1
,
'elements'
=>
'*+embed+object-form'
,
'elements'
=>
'*+embed+object-form'
,
'schemes'
=>
'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https; style: !; classid:clsid'
,
'schemes'
=>
'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https; style: !; classid:clsid'
,
...
@@ -890,166 +918,166 @@
...
@@ -890,166 +918,166 @@
));
));
return
$safe
;
return
$safe
;
}
}
/**
/**
* htmLawed hook function used to process tags in qa_sanitize_html(...)
* htmLawed hook function used to process tags in qa_sanitize_html(...)
*/
*/
function
qa_sanitize_html_hook_tag
(
$element
,
$attributes
=
null
)
function
qa_sanitize_html_hook_tag
(
$element
,
$attributes
=
null
)
{
{
global
$qa_sanitize_html_newwindow
;
global
$qa_sanitize_html_newwindow
;
if
(
!
isset
(
$attributes
))
// it's a closing tag
if
(
!
isset
(
$attributes
))
// it's a closing tag
return
'</'
.
$element
.
'>'
;
return
'</'
.
$element
.
'>'
;
if
(
(
$element
==
'param'
)
&&
(
trim
(
strtolower
(
@
$attributes
[
'name'
]))
==
'allowscriptaccess'
)
)
if
((
$element
==
'param'
)
&&
(
trim
(
strtolower
(
@
$attributes
[
'name'
]))
==
'allowscriptaccess'
)
)
$attributes
[
'name'
]
=
'allowscriptaccess_denied'
;
$attributes
[
'name'
]
=
'allowscriptaccess_denied'
;
if
(
$element
==
'embed'
)
if
(
$element
==
'embed'
)
unset
(
$attributes
[
'allowscriptaccess'
]);
unset
(
$attributes
[
'allowscriptaccess'
]);
if
((
$element
==
'a'
)
&&
isset
(
$attributes
[
'href'
])
&&
$qa_sanitize_html_newwindow
)
if
((
$element
==
'a'
)
&&
isset
(
$attributes
[
'href'
])
&&
$qa_sanitize_html_newwindow
)
$attributes
[
'target'
]
=
'_blank'
;
$attributes
[
'target'
]
=
'_blank'
;
$html
=
'<'
.
$element
;
$html
=
'<'
.
$element
;
foreach
(
$attributes
as
$key
=>
$value
)
foreach
(
$attributes
as
$key
=>
$value
)
$html
.=
' '
.
$key
.
'="'
.
$value
.
'"'
;
$html
.=
' '
.
$key
.
'="'
.
$value
.
'"'
;
return
$html
.
'>'
;
return
$html
.
'>'
;
}
}
/**
/**
* Return XML representation of $string, which is similar to HTML but ASCII control characters are also disallowed
* Return XML representation of $string, which is similar to HTML but ASCII control characters are also disallowed
*/
*/
function
qa_xml
(
$string
)
function
qa_xml
(
$string
)
{
{
return
htmlspecialchars
(
preg_replace
(
'/[\x00-\x08\x0B\x0C\x0E-\x1F]/'
,
''
,
(
string
)
$string
));
return
htmlspecialchars
(
preg_replace
(
'/[\x00-\x08\x0B\x0C\x0E-\x1F]/'
,
''
,
(
string
)
$string
));
}
}
/**
/**
* Return JavaScript representation of $value, putting in quotes if non-numeric or if $forcequotes is true. In the
* Return JavaScript representation of $value, putting in quotes if non-numeric or if $forcequotes is true. In the
* case of boolean values they are returned as the appropriate true or false string
* case of boolean values they are returned as the appropriate true or false string
*/
*/
function
qa_js
(
$value
,
$forcequotes
=
false
)
function
qa_js
(
$value
,
$forcequotes
=
false
)
{
{
$boolean
=
is_bool
(
$value
);
$boolean
=
is_bool
(
$value
);
if
(
$boolean
)
if
(
$boolean
)
$value
=
$value
?
'true'
:
'false'
;
$value
=
$value
?
'true'
:
'false'
;
if
((
is_numeric
(
$value
)
||
$boolean
)
&&
!
$forcequotes
)
if
((
is_numeric
(
$value
)
||
$boolean
)
&&
!
$forcequotes
)
return
$value
;
return
$value
;
else
else
return
"'"
.
strtr
(
$value
,
array
(
return
"'"
.
strtr
(
$value
,
array
(
"'"
=>
"
\\
'"
,
"'"
=>
"
\\
'"
,
'/'
=>
'\\/'
,
'/'
=>
'\\/'
,
'\\'
=>
'\\\\'
,
'\\'
=>
'\\\\'
,
"
\n
"
=>
"
\\
n"
,
"
\n
"
=>
"
\\
n"
,
"
\r
"
=>
"
\\
n"
,
"
\r
"
=>
"
\\
n"
,
))
.
"'"
;
))
.
"'"
;
}
}
// Finding out more about the current request
// Finding out more about the current request
/**
/**
* Inform Q2A that the current request is $request (slash-separated, independent of the url scheme chosen),
* Inform Q2A that the current request is $request (slash-separated, independent of the url scheme chosen),
* that the relative path to the Q2A root apperas to be $relativeroot, and the url scheme appears to be $usedformat
* that the relative path to the Q2A root apperas to be $relativeroot, and the url scheme appears to be $usedformat
*/
*/
function
qa_set_request
(
$request
,
$relativeroot
,
$usedformat
=
null
)
function
qa_set_request
(
$request
,
$relativeroot
,
$usedformat
=
null
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_request
,
$qa_root_url_relative
,
$qa_used_url_format
;
global
$qa_request
,
$qa_root_url_relative
,
$qa_used_url_format
;
$qa_request
=
$request
;
$qa_request
=
$request
;
$qa_root_url_relative
=
$relativeroot
;
$qa_root_url_relative
=
$relativeroot
;
$qa_used_url_format
=
$usedformat
;
$qa_used_url_format
=
$usedformat
;
}
}
/**
/**
* Returns the current Q2A request (slash-separated, independent of the url scheme chosen)
* Returns the current Q2A request (slash-separated, independent of the url scheme chosen)
*/
*/
function
qa_request
()
function
qa_request
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_request
;
global
$qa_request
;
return
$qa_request
;
return
$qa_request
;
}
}
/**
/**
* Returns the indexed $part (as separated by slashes) of the current Q2A request, or null if it doesn't exist
* Returns the indexed $part (as separated by slashes) of the current Q2A request, or null if it doesn't exist
*/
*/
function
qa_request_part
(
$part
)
function
qa_request_part
(
$part
)
{
{
$parts
=
explode
(
'/'
,
qa_request
());
$parts
=
explode
(
'/'
,
qa_request
());
return
@
$parts
[
$part
];
return
@
$parts
[
$part
];
}
}
/**
/**
* Returns an array of parts (as separated by slashes) of the current Q2A request, starting at part $start
* Returns an array of parts (as separated by slashes) of the current Q2A request, starting at part $start
*/
*/
function
qa_request_parts
(
$start
=
0
)
function
qa_request_parts
(
$start
=
0
)
{
{
return
array_slice
(
explode
(
'/'
,
qa_request
()),
$start
);
return
array_slice
(
explode
(
'/'
,
qa_request
()),
$start
);
}
}
/**
/**
* Return string for incoming GET/POST/COOKIE value, stripping slashes if appropriate
* Return string for incoming GET/POST/COOKIE value, stripping slashes if appropriate
*/
*/
function
qa_gpc_to_string
(
$string
)
function
qa_gpc_to_string
(
$string
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
get_magic_quotes_gpc
()
?
stripslashes
(
$string
)
:
$string
;
return
get_magic_quotes_gpc
()
?
stripslashes
(
$string
)
:
$string
;
}
}
/**
/**
* Return string with slashes added, if appropriate for later removal by qa_gpc_to_string()
* Return string with slashes added, if appropriate for later removal by qa_gpc_to_string()
*/
*/
function
qa_string_to_gpc
(
$string
)
function
qa_string_to_gpc
(
$string
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
get_magic_quotes_gpc
()
?
addslashes
(
$string
)
:
$string
;
return
get_magic_quotes_gpc
()
?
addslashes
(
$string
)
:
$string
;
}
}
/**
/**
* Return string for incoming GET field, or null if it's not defined
* Return string for incoming GET field, or null if it's not defined
*/
*/
function
qa_get
(
$field
)
function
qa_get
(
$field
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
isset
(
$_GET
[
$field
])
?
qa_gpc_to_string
(
$_GET
[
$field
])
:
null
;
return
isset
(
$_GET
[
$field
])
?
qa_gpc_to_string
(
$_GET
[
$field
])
:
null
;
}
}
/**
/**
* Return string for incoming POST field, or null if it's not defined.
* Return string for incoming POST field, or null if it's not defined.
* While we're at it, trim() surrounding white space and converted to Unix line endings.
* While we're at it, trim() surrounding white space and converted to Unix line endings.
*/
*/
function
qa_post_text
(
$field
)
function
qa_post_text
(
$field
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
isset
(
$_POST
[
$field
])
?
preg_replace
(
'/\r\n?/'
,
"
\n
"
,
trim
(
qa_gpc_to_string
(
$_POST
[
$field
])))
:
null
;
return
isset
(
$_POST
[
$field
])
?
preg_replace
(
'/\r\n?/'
,
"
\n
"
,
trim
(
qa_gpc_to_string
(
$_POST
[
$field
])))
:
null
;
}
}
/**
/**
* Return an array for incoming POST field, or null if it's not an array or not defined.
* Return an array for incoming POST field, or null if it's not an array or not defined.
* While we're at it, trim() surrounding white space for each value and convert them to Unix line endings.
* While we're at it, trim() surrounding white space for each value and convert them to Unix line endings.
*/
*/
function
qa_post_array
(
$field
)
function
qa_post_array
(
$field
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
!
isset
(
$_POST
[
$field
])
||
!
is_array
(
$_POST
[
$field
]))
{
if
(
!
isset
(
$_POST
[
$field
])
||
!
is_array
(
$_POST
[
$field
]))
{
...
@@ -1061,41 +1089,41 @@
...
@@ -1061,41 +1089,41 @@
$result
[
$key
]
=
preg_replace
(
'/\r\n?/'
,
"
\n
"
,
trim
(
qa_gpc_to_string
(
$value
)));
$result
[
$key
]
=
preg_replace
(
'/\r\n?/'
,
"
\n
"
,
trim
(
qa_gpc_to_string
(
$value
)));
return
$result
;
return
$result
;
}
}
/**
/**
* Return true if form button $name was clicked (as type=submit/image) to create this page request, or if a
* Return true if form button $name was clicked (as type=submit/image) to create this page request, or if a
* simulated click was sent for the button (via 'qa_click' POST field)
* simulated click was sent for the button (via 'qa_click' POST field)
*/
*/
function
qa_clicked
(
$name
)
function
qa_clicked
(
$name
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
isset
(
$_POST
[
$name
])
||
isset
(
$_POST
[
$name
.
'_x'
])
||
(
qa_post_text
(
'qa_click'
)
==
$name
);
return
isset
(
$_POST
[
$name
])
||
isset
(
$_POST
[
$name
.
'_x'
])
||
(
qa_post_text
(
'qa_click'
)
==
$name
);
}
}
/**
/**
* Determine the remote IP address of the user accessing the site.
* Determine the remote IP address of the user accessing the site.
* @return mixed String representing IP if it's available, or null otherwise.
* @return mixed String representing IP if it's available, or null otherwise.
*/
*/
function
qa_remote_ip_address
()
function
qa_remote_ip_address
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
isset
(
$_SERVER
[
'REMOTE_ADDR'
])
?
$_SERVER
[
'REMOTE_ADDR'
]
:
null
;
return
isset
(
$_SERVER
[
'REMOTE_ADDR'
])
?
$_SERVER
[
'REMOTE_ADDR'
]
:
null
;
}
}
/**
/**
* Checks whether an HTTP request has exceeded the post_max_size PHP variable. This happens whenever an HTTP request
* Checks whether an HTTP request has exceeded the post_max_size PHP variable. This happens whenever an HTTP request
* is too big to be properly processed by PHP, usually because there is an attachment in the HTTP request. A warning
* is too big to be properly processed by PHP, usually because there is an attachment in the HTTP request. A warning
* is added to the server's log displaying the size of the file that triggered this situation. It is important to note
* is added to the server's log displaying the size of the file that triggered this situation. It is important to note
* that whenever this happens the $_POST and $_FILES superglobals are empty.
* that whenever this happens the $_POST and $_FILES superglobals are empty.
*/
*/
function
qa_post_limit_exceeded
()
function
qa_post_limit_exceeded
()
{
{
if
(
in_array
(
$_SERVER
[
'REQUEST_METHOD'
],
array
(
'POST'
,
'PUT'
))
&&
empty
(
$_POST
)
&&
empty
(
$_FILES
))
{
if
(
in_array
(
$_SERVER
[
'REQUEST_METHOD'
],
array
(
'POST'
,
'PUT'
))
&&
empty
(
$_POST
)
&&
empty
(
$_FILES
))
{
$postmaxsize
=
ini_get
(
'post_max_size'
);
// Gets the current post_max_size configuration
$postmaxsize
=
ini_get
(
'post_max_size'
);
// Gets the current post_max_size configuration
$unit
=
substr
(
$postmaxsize
,
-
1
);
$unit
=
substr
(
$postmaxsize
,
-
1
);
...
@@ -1106,18 +1134,18 @@
...
@@ -1106,18 +1134,18 @@
$postmaxsize
=
convert_to_bytes
(
$unit
,
$postmaxsize
);
$postmaxsize
=
convert_to_bytes
(
$unit
,
$postmaxsize
);
return
$_SERVER
[
'CONTENT_LENGTH'
]
>
$postmaxsize
;
return
$_SERVER
[
'CONTENT_LENGTH'
]
>
$postmaxsize
;
}
}
}
}
/**
/**
* Turns a numeric value and a unit (g/m/k) into bytes
* Turns a numeric value and a unit (g/m/k) into bytes
* @param string $unit One of 'g', 'm', 'k'. It is case insensitive
* @param string $unit One of 'g', 'm', 'k'. It is case insensitive
* @param int $value The value to turn into bytes
* @param int $value The value to turn into bytes
* @return int The amount of bytes the unit and the value represent. If the unit is not one of 'g', 'm' or 'k' then
* @return int The amount of bytes the unit and the value represent. If the unit is not one of 'g', 'm' or 'k' then
* the original value is returned
* the original value is returned
*/
*/
function
convert_to_bytes
(
$unit
,
$value
)
function
convert_to_bytes
(
$unit
,
$value
)
{
{
switch
(
strtolower
(
$unit
))
{
switch
(
strtolower
(
$unit
))
{
case
'g'
:
case
'g'
:
return
$value
*
1073741824
;
return
$value
*
1073741824
;
...
@@ -1128,78 +1156,78 @@
...
@@ -1128,78 +1156,78 @@
default
:
default
:
return
$value
;
return
$value
;
}
}
}
}
/**
/**
* Whether we are responding to an HTTP GET request
* Whether we are responding to an HTTP GET request
* @return bool True if the request is GET
* @return bool True if the request is GET
*/
*/
function
qa_is_http_get
()
function
qa_is_http_get
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
$_SERVER
[
'REQUEST_METHOD'
]
===
'GET'
;
return
$_SERVER
[
'REQUEST_METHOD'
]
===
'GET'
;
}
}
/**
/**
* Return true if we are responding to an HTTP POST request
* Return true if we are responding to an HTTP POST request
*/
*/
function
qa_is_http_post
()
function
qa_is_http_post
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
$_SERVER
[
'REQUEST_METHOD'
]
===
'POST'
||
!
empty
(
$_POST
);
return
$_SERVER
[
'REQUEST_METHOD'
]
===
'POST'
||
!
empty
(
$_POST
);
}
}
/**
/**
* Return true if we appear to be responding to a secure HTTP request (but hard to be sure)
* Return true if we appear to be responding to a secure HTTP request (but hard to be sure)
*/
*/
function
qa_is_https_probably
()
function
qa_is_https_probably
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
(
@
$_SERVER
[
'HTTPS'
]
&&
(
$_SERVER
[
'HTTPS'
]
!=
'off'
))
||
(
@
$_SERVER
[
'SERVER_PORT'
]
==
443
);
return
(
@
$_SERVER
[
'HTTPS'
]
&&
(
$_SERVER
[
'HTTPS'
]
!=
'off'
))
||
(
@
$_SERVER
[
'SERVER_PORT'
]
==
443
);
}
}
/**
/**
* Return true if it appears the page request is coming from a human using a web browser, rather than a search engine
* Return true if it appears the page request is coming from a human using a web browser, rather than a search engine
* or other bot. Based on a whitelist of terms in user agents, this can easily be tricked by a scraper or bad bot.
* or other bot. Based on a whitelist of terms in user agents, this can easily be tricked by a scraper or bad bot.
*/
*/
function
qa_is_human_probably
()
function
qa_is_human_probably
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
require_once
QA_INCLUDE_DIR
.
'util/string.php'
;
require_once
QA_INCLUDE_DIR
.
'util/string.php'
;
$useragent
=
@
$_SERVER
[
'HTTP_USER_AGENT'
];
$useragent
=
@
$_SERVER
[
'HTTP_USER_AGENT'
];
return
(
strlen
(
$useragent
)
==
0
)
||
qa_string_matches_one
(
$useragent
,
array
(
return
(
strlen
(
$useragent
)
==
0
)
||
qa_string_matches_one
(
$useragent
,
array
(
'MSIE'
,
'Firefox'
,
'Chrome'
,
'Safari'
,
'Opera'
,
'Gecko'
,
'MIDP'
,
'PLAYSTATION'
,
'Teleca'
,
'MSIE'
,
'Firefox'
,
'Chrome'
,
'Safari'
,
'Opera'
,
'Gecko'
,
'MIDP'
,
'PLAYSTATION'
,
'Teleca'
,
'BlackBerry'
,
'UP.Browser'
,
'Polaris'
,
'MAUI_WAP_Browser'
,
'iPad'
,
'iPhone'
,
'iPod'
'BlackBerry'
,
'UP.Browser'
,
'Polaris'
,
'MAUI_WAP_Browser'
,
'iPad'
,
'iPhone'
,
'iPod'
,
));
));
}
}
/**
/**
* Return true if it appears that the page request is coming from a mobile client rather than a desktop/laptop web browser
* Return true if it appears that the page request is coming from a mobile client rather than a desktop/laptop web browser
*/
*/
function
qa_is_mobile_probably
()
function
qa_is_mobile_probably
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
require_once
QA_INCLUDE_DIR
.
'util/string.php'
;
require_once
QA_INCLUDE_DIR
.
'util/string.php'
;
// inspired by: http://dangerousprototypes.com/docs/PhpBB3_MOD:_Replacement_mobile_browser_detection_for_mobile_themes
// inspired by: http://dangerousprototypes.com/docs/PhpBB3_MOD:_Replacement_mobile_browser_detection_for_mobile_themes
$loweragent
=
strtolower
(
@
$_SERVER
[
'HTTP_USER_AGENT'
]);
$loweragent
=
strtolower
(
@
$_SERVER
[
'HTTP_USER_AGENT'
]);
if
(
strpos
(
$loweragent
,
'ipad'
)
!==
false
)
// consider iPad as desktop
if
(
strpos
(
$loweragent
,
'ipad'
)
!==
false
)
// consider iPad as desktop
return
false
;
return
false
;
$mobileheaders
=
array
(
'HTTP_X_OPERAMINI_PHONE'
,
'HTTP_X_WAP_PROFILE'
,
'HTTP_PROFILE'
);
$mobileheaders
=
array
(
'HTTP_X_OPERAMINI_PHONE'
,
'HTTP_X_WAP_PROFILE'
,
'HTTP_PROFILE'
);
foreach
(
$mobileheaders
as
$header
)
foreach
(
$mobileheaders
as
$header
)
if
(
isset
(
$_SERVER
[
$header
]))
if
(
isset
(
$_SERVER
[
$header
]))
...
@@ -1208,27 +1236,27 @@
...
@@ -1208,27 +1236,27 @@
if
(
qa_string_matches_one
(
$loweragent
,
array
(
if
(
qa_string_matches_one
(
$loweragent
,
array
(
'android'
,
'phone'
,
'mobile'
,
'windows ce'
,
'palm'
,
' mobi'
,
'wireless'
,
'blackberry'
,
'opera mini'
,
'symbian'
,
'android'
,
'phone'
,
'mobile'
,
'windows ce'
,
'palm'
,
' mobi'
,
'wireless'
,
'blackberry'
,
'opera mini'
,
'symbian'
,
'nokia'
,
'samsung'
,
'ericsson,'
,
'vodafone/'
,
'kindle'
,
'ipod'
,
'wap1.'
,
'wap2.'
,
'sony'
,
'sanyo'
,
'sharp'
,
'nokia'
,
'samsung'
,
'ericsson,'
,
'vodafone/'
,
'kindle'
,
'ipod'
,
'wap1.'
,
'wap2.'
,
'sony'
,
'sanyo'
,
'sharp'
,
'panasonic'
,
'philips'
,
'pocketpc'
,
'avantgo'
,
'blazer'
,
'ipaq'
,
'up.browser'
,
'up.link'
,
'mmp'
,
'smartphone'
,
'midp'
'panasonic'
,
'philips'
,
'pocketpc'
,
'avantgo'
,
'blazer'
,
'ipaq'
,
'up.browser'
,
'up.link'
,
'mmp'
,
'smartphone'
,
'midp'
,
)))
)))
return
true
;
return
true
;
return
qa_string_matches_one
(
strtolower
(
@
$_SERVER
[
'HTTP_ACCEPT'
]),
array
(
return
qa_string_matches_one
(
strtolower
(
@
$_SERVER
[
'HTTP_ACCEPT'
]),
array
(
'application/vnd.wap.xhtml+xml'
,
'text/vnd.wap.wml'
'application/vnd.wap.xhtml+xml'
,
'text/vnd.wap.wml'
,
));
));
}
}
// Language phrase support
// Language phrase support
/**
/**
* Return the translated string for $identifier, unless we're using external translation logic.
* Return the translated string for $identifier, unless we're using external translation logic.
* This will retrieve the 'site_language' option so make sure you've already loaded/set that if
* This will retrieve the 'site_language' option so make sure you've already loaded/set that if
* loading an option now will cause a problem (see issue in qa_default_option()). The part of
* loading an option now will cause a problem (see issue in qa_default_option()). The part of
* $identifier before the slash (/) replaces the * in the qa-lang-*.php file references, and the
* $identifier before the slash (/) replaces the * in the qa-lang-*.php file references, and the
* part after the / is the key of the array element to be taken from that file's returned result.
* part after the / is the key of the array element to be taken from that file's returned result.
*/
*/
function
qa_lang
(
$identifier
)
function
qa_lang
(
$identifier
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_lang_file_pattern
,
$qa_phrases_full
;
global
$qa_lang_file_pattern
,
$qa_phrases_full
;
...
@@ -1243,7 +1271,7 @@
...
@@ -1243,7 +1271,7 @@
if
(
isset
(
$qa_lang_file_pattern
[
$group
]))
if
(
isset
(
$qa_lang_file_pattern
[
$group
]))
$include
=
str_replace
(
'*'
,
'default'
,
$qa_lang_file_pattern
[
$group
]);
$include
=
str_replace
(
'*'
,
'default'
,
$qa_lang_file_pattern
[
$group
]);
else
else
$include
=
QA_INCLUDE_DIR
.
'lang/qa-lang-'
.
$group
.
'.php'
;
$include
=
QA_INCLUDE_DIR
.
'lang/qa-lang-'
.
$group
.
'.php'
;
$qa_phrases_full
[
$group
]
=
is_file
(
$include
)
?
(
array
)(
include_once
$include
)
:
array
();
$qa_phrases_full
[
$group
]
=
is_file
(
$include
)
?
(
array
)(
include_once
$include
)
:
array
();
...
@@ -1253,14 +1281,14 @@
...
@@ -1253,14 +1281,14 @@
if
(
isset
(
$qa_lang_file_pattern
[
$group
]))
if
(
isset
(
$qa_lang_file_pattern
[
$group
]))
$include
=
str_replace
(
'*'
,
$languagecode
,
$qa_lang_file_pattern
[
$group
]);
$include
=
str_replace
(
'*'
,
$languagecode
,
$qa_lang_file_pattern
[
$group
]);
else
else
$include
=
QA_LANG_DIR
.
$languagecode
.
'/qa-lang-'
.
$group
.
'.php'
;
$include
=
QA_LANG_DIR
.
$languagecode
.
'/qa-lang-'
.
$group
.
'.php'
;
$phrases
=
is_file
(
$include
)
?
(
array
)(
include
$include
)
:
array
();
$phrases
=
is_file
(
$include
)
?
(
array
)(
include
$include
)
:
array
();
$qa_phrases_full
[
$group
]
=
array_merge
(
$qa_phrases_full
[
$group
],
$phrases
);
$qa_phrases_full
[
$group
]
=
array_merge
(
$qa_phrases_full
[
$group
],
$phrases
);
}
}
// add any custom phrases from qa-lang/custom/
// add any custom phrases from qa-lang/custom/
$include
=
QA_LANG_DIR
.
'custom/qa-lang-'
.
$group
.
'.php'
;
$include
=
QA_LANG_DIR
.
'custom/qa-lang-'
.
$group
.
'.php'
;
$phrases
=
is_file
(
$include
)
?
(
array
)(
include
$include
)
:
array
();
$phrases
=
is_file
(
$include
)
?
(
array
)(
include
$include
)
:
array
();
$qa_phrases_full
[
$group
]
=
array_merge
(
$qa_phrases_full
[
$group
],
$phrases
);
$qa_phrases_full
[
$group
]
=
array_merge
(
$qa_phrases_full
[
$group
],
$phrases
);
...
@@ -1268,180 +1296,182 @@
...
@@ -1268,180 +1296,182 @@
return
$qa_phrases_full
[
$group
][
$label
];
return
$qa_phrases_full
[
$group
][
$label
];
}
}
return
'['
.
$identifier
.
']'
;
// as a last resort, return the identifier to help in development
return
'['
.
$identifier
.
']'
;
// as a last resort, return the identifier to help in development
}
}
/**
/**
* Return the translated string for $identifier, with $symbol substituted for $textparam
* Return the translated string for $identifier, with $symbol substituted for $textparam
*/
*/
function
qa_lang_sub
(
$identifier
,
$textparam
,
$symbol
=
'^'
)
function
qa_lang_sub
(
$identifier
,
$textparam
,
$symbol
=
'^'
)
{
{
return
str_replace
(
$symbol
,
$textparam
,
qa_lang
(
$identifier
));
return
str_replace
(
$symbol
,
$textparam
,
qa_lang
(
$identifier
));
}
}
/**
/**
* Return the translated string for $identifier, converted to HTML
* Return the translated string for $identifier, converted to HTML
*/
*/
function
qa_lang_html
(
$identifier
)
function
qa_lang_html
(
$identifier
)
{
{
return
qa_html
(
qa_lang
(
$identifier
));
return
qa_html
(
qa_lang
(
$identifier
));
}
}
/**
/**
* Return the translated string for $identifier converted to HTML, with $symbol *then* substituted for $htmlparam
* Return the translated string for $identifier converted to HTML, with $symbol *then* substituted for $htmlparam
*/
*/
function
qa_lang_html_sub
(
$identifier
,
$htmlparam
,
$symbol
=
'^'
)
function
qa_lang_html_sub
(
$identifier
,
$htmlparam
,
$symbol
=
'^'
)
{
{
return
str_replace
(
$symbol
,
$htmlparam
,
qa_lang_html
(
$identifier
));
return
str_replace
(
$symbol
,
$htmlparam
,
qa_lang_html
(
$identifier
));
}
}
/**
/**
* Return an array containing the translated string for $identifier converted to HTML, then split into three,
* Return an array containing the translated string for $identifier converted to HTML, then split into three,
* with $symbol substituted for $htmlparam in the 'data' element, and obvious 'prefix' and 'suffix' elements
* with $symbol substituted for $htmlparam in the 'data' element, and obvious 'prefix' and 'suffix' elements
*/
*/
function
qa_lang_html_sub_split
(
$identifier
,
$htmlparam
,
$symbol
=
'^'
)
function
qa_lang_html_sub_split
(
$identifier
,
$htmlparam
,
$symbol
=
'^'
)
{
{
$html
=
qa_lang_html
(
$identifier
);
$html
=
qa_lang_html
(
$identifier
);
$symbolpos
=
strpos
(
$html
,
$symbol
);
$symbolpos
=
strpos
(
$html
,
$symbol
);
if
(
!
is_numeric
(
$symbolpos
))
if
(
!
is_numeric
(
$symbolpos
))
qa_fatal_error
(
'Missing '
.
$symbol
.
' in language string '
.
$identifier
);
qa_fatal_error
(
'Missing '
.
$symbol
.
' in language string '
.
$identifier
);
return
array
(
return
array
(
'prefix'
=>
substr
(
$html
,
0
,
$symbolpos
),
'prefix'
=>
substr
(
$html
,
0
,
$symbolpos
),
'data'
=>
$htmlparam
,
'data'
=>
$htmlparam
,
'suffix'
=>
substr
(
$html
,
$symbolpos
+
1
),
'suffix'
=>
substr
(
$html
,
$symbolpos
+
1
),
);
);
}
}
// Request and path generation
// Request and path generation
/**
/**
* Return the relative path to the Q2A root (if it was previously set by qa_set_request())
* Return the relative path to the Q2A root (if it was previously set by qa_set_request())
*/
*/
function
qa_path_to_root
()
function
qa_path_to_root
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_root_url_relative
;
global
$qa_root_url_relative
;
return
$qa_root_url_relative
;
return
$qa_root_url_relative
;
}
}
/**
/**
* Return an array of mappings of Q2A requests, as defined in the qa-config.php file
* Return an array of mappings of Q2A requests, as defined in the qa-config.php file
*/
*/
function
qa_get_request_map
()
function
qa_get_request_map
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_request_map
;
global
$qa_request_map
;
return
$qa_request_map
;
return
$qa_request_map
;
}
}
/**
/**
* Return the relative URI path for $request, with optional parameters $params and $anchor.
* Return the relative URI path for $request, with optional parameters $params and $anchor.
* Slashes in $request will not be urlencoded, but any other characters will.
* Slashes in $request will not be urlencoded, but any other characters will.
* If $neaturls is set, use that, otherwise retrieve the option. If $rooturl is set, take
* If $neaturls is set, use that, otherwise retrieve the option. If $rooturl is set, take
* that as the root of the Q2A site, otherwise use path to root which was set elsewhere.
* that as the root of the Q2A site, otherwise use path to root which was set elsewhere.
*/
*/
function
qa_path
(
$request
,
$params
=
null
,
$rooturl
=
null
,
$neaturls
=
null
,
$anchor
=
null
)
function
qa_path
(
$request
,
$params
=
null
,
$rooturl
=
null
,
$neaturls
=
null
,
$anchor
=
null
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
!
isset
(
$neaturls
))
{
if
(
!
isset
(
$neaturls
))
{
require_once
QA_INCLUDE_DIR
.
'app/options.php'
;
require_once
QA_INCLUDE_DIR
.
'app/options.php'
;
$neaturls
=
qa_opt
(
'neat_urls'
);
$neaturls
=
qa_opt
(
'neat_urls'
);
}
}
if
(
!
isset
(
$rooturl
))
if
(
!
isset
(
$rooturl
))
$rooturl
=
qa_path_to_root
();
$rooturl
=
qa_path_to_root
();
$url
=
$rooturl
.
(
(
empty
(
$rooturl
)
||
(
substr
(
$rooturl
,
-
1
)
==
'/'
)
)
?
''
:
'/'
);
$url
=
$rooturl
.
((
empty
(
$rooturl
)
||
(
substr
(
$rooturl
,
-
1
)
==
'/'
)
)
?
''
:
'/'
);
$paramsextra
=
''
;
$paramsextra
=
''
;
$requestparts
=
explode
(
'/'
,
$request
);
$requestparts
=
explode
(
'/'
,
$request
);
$pathmap
=
qa_get_request_map
();
$pathmap
=
qa_get_request_map
();
if
(
isset
(
$pathmap
[
$requestparts
[
0
]]))
{
if
(
isset
(
$pathmap
[
$requestparts
[
0
]]))
{
$newpart
=
$pathmap
[
$requestparts
[
0
]];
$newpart
=
$pathmap
[
$requestparts
[
0
]];
if
(
strlen
(
$newpart
))
if
(
strlen
(
$newpart
))
$requestparts
[
0
]
=
$newpart
;
$requestparts
[
0
]
=
$newpart
;
elseif
(
count
(
$requestparts
)
==
1
)
elseif
(
count
(
$requestparts
)
==
1
)
array_shift
(
$requestparts
);
array_shift
(
$requestparts
);
}
}
foreach
(
$requestparts
as
$index
=>
$requestpart
)
foreach
(
$requestparts
as
$index
=>
$requestpart
)
{
$requestparts
[
$index
]
=
urlencode
(
$requestpart
);
$requestparts
[
$index
]
=
urlencode
(
$requestpart
);
$requestpath
=
implode
(
'/'
,
$requestparts
);
}
$requestpath
=
implode
(
'/'
,
$requestparts
);
switch
(
$neaturls
)
{
switch
(
$neaturls
)
{
case
QA_URL_FORMAT_INDEX
:
case
QA_URL_FORMAT_INDEX
:
if
(
!
empty
(
$request
))
if
(
!
empty
(
$request
))
$url
.=
'index.php/'
.
$requestpath
;
$url
.=
'index.php/'
.
$requestpath
;
break
;
break
;
case
QA_URL_FORMAT_NEAT
:
case
QA_URL_FORMAT_NEAT
:
$url
.=
$requestpath
;
$url
.=
$requestpath
;
break
;
break
;
case
QA_URL_FORMAT_PARAM
:
case
QA_URL_FORMAT_PARAM
:
if
(
!
empty
(
$request
))
if
(
!
empty
(
$request
))
$paramsextra
=
'?qa='
.
$requestpath
;
$paramsextra
=
'?qa='
.
$requestpath
;
break
;
break
;
default
:
default
:
$url
.=
'index.php'
;
$url
.=
'index.php'
;
case
QA_URL_FORMAT_PARAMS
:
case
QA_URL_FORMAT_PARAMS
:
if
(
!
empty
(
$request
))
if
(
!
empty
(
$request
))
{
foreach
(
$requestparts
as
$partindex
=>
$requestpart
)
foreach
(
$requestparts
as
$partindex
=>
$requestpart
)
$paramsextra
.=
(
strlen
(
$paramsextra
)
?
'&'
:
'?'
)
.
'qa'
.
(
$partindex
?
(
'_'
.
$partindex
)
:
''
)
.
'='
.
$requestpart
;
$paramsextra
.=
(
strlen
(
$paramsextra
)
?
'&'
:
'?'
)
.
'qa'
.
(
$partindex
?
(
'_'
.
$partindex
)
:
''
)
.
'='
.
$requestpart
;
}
break
;
break
;
}
}
if
(
isset
(
$params
))
if
(
isset
(
$params
))
foreach
(
$params
as
$key
=>
$value
)
foreach
(
$params
as
$key
=>
$value
)
$paramsextra
.=
(
strlen
(
$paramsextra
)
?
'&'
:
'?'
)
.
urlencode
(
$key
)
.
'='
.
urlencode
((
string
)
$value
);
$paramsextra
.=
(
strlen
(
$paramsextra
)
?
'&'
:
'?'
)
.
urlencode
(
$key
)
.
'='
.
urlencode
((
string
)
$value
);
return
$url
.
$paramsextra
.
(
empty
(
$anchor
)
?
''
:
'#'
.
urlencode
(
$anchor
)
);
return
$url
.
$paramsextra
.
(
empty
(
$anchor
)
?
''
:
'#'
.
urlencode
(
$anchor
)
);
}
}
/**
/**
* Return HTML representation of relative URI path for $request - see qa_path() for other parameters
* Return HTML representation of relative URI path for $request - see qa_path() for other parameters
*/
*/
function
qa_path_html
(
$request
,
$params
=
null
,
$rooturl
=
null
,
$neaturls
=
null
,
$anchor
=
null
)
function
qa_path_html
(
$request
,
$params
=
null
,
$rooturl
=
null
,
$neaturls
=
null
,
$anchor
=
null
)
{
{
return
qa_html
(
qa_path
(
$request
,
$params
,
$rooturl
,
$neaturls
,
$anchor
));
return
qa_html
(
qa_path
(
$request
,
$params
,
$rooturl
,
$neaturls
,
$anchor
));
}
}
/**
/**
* Return the absolute URI for $request - see qa_path() for other parameters
* Return the absolute URI for $request - see qa_path() for other parameters
*/
*/
function
qa_path_absolute
(
$request
,
$params
=
null
,
$anchor
=
null
)
function
qa_path_absolute
(
$request
,
$params
=
null
,
$anchor
=
null
)
{
{
return
qa_path
(
$request
,
$params
,
qa_opt
(
'site_url'
),
null
,
$anchor
);
return
qa_path
(
$request
,
$params
,
qa_opt
(
'site_url'
),
null
,
$anchor
);
}
}
/**
/**
* Get Q2A request for a question, and make it search-engine friendly, shortening it if necessary
* Get Q2A request for a question, and make it search-engine friendly, shortening it if necessary
* by removing shorter words which are generally less meaningful.
* by removing shorter words which are generally less meaningful.
* @param int $questionid The question ID
* @param int $questionid The question ID
* @param string $title The question title
* @param string $title The question title
* @return string
* @return string
*/
*/
function
qa_q_request
(
$questionid
,
$title
)
function
qa_q_request
(
$questionid
,
$title
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
require_once
QA_INCLUDE_DIR
.
'app/options.php'
;
require_once
QA_INCLUDE_DIR
.
'app/options.php'
;
...
@@ -1450,129 +1480,129 @@
...
@@ -1450,129 +1480,129 @@
$title
=
qa_block_words_replace
(
$title
,
qa_get_block_words_preg
());
$title
=
qa_block_words_replace
(
$title
,
qa_get_block_words_preg
());
$slug
=
qa_slugify
(
$title
,
qa_opt
(
'q_urls_remove_accents'
),
qa_opt
(
'q_urls_title_length'
));
$slug
=
qa_slugify
(
$title
,
qa_opt
(
'q_urls_remove_accents'
),
qa_opt
(
'q_urls_title_length'
));
return
(
int
)
$questionid
.
'/'
.
$slug
;
return
(
int
)
$questionid
.
'/'
.
$slug
;
}
}
/**
/**
* Return the HTML anchor that should be used for post $postid with $basetype (Q/A/C)
* Return the HTML anchor that should be used for post $postid with $basetype (Q/A/C)
*/
*/
function
qa_anchor
(
$basetype
,
$postid
)
function
qa_anchor
(
$basetype
,
$postid
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
strtolower
(
$basetype
)
.
$postid
;
// used to be $postid only but this violated HTML spec
return
strtolower
(
$basetype
)
.
$postid
;
// used to be $postid only but this violated HTML spec
}
}
/**
/**
* Return the URL for question $questionid with $title, possibly using $absolute URLs.
* Return the URL for question $questionid with $title, possibly using $absolute URLs.
* To link to a specific answer or comment in a question, set $showtype and $showid accordingly.
* To link to a specific answer or comment in a question, set $showtype and $showid accordingly.
*/
*/
function
qa_q_path
(
$questionid
,
$title
,
$absolute
=
false
,
$showtype
=
null
,
$showid
=
null
)
function
qa_q_path
(
$questionid
,
$title
,
$absolute
=
false
,
$showtype
=
null
,
$showid
=
null
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
((
$showtype
==
'Q'
)
||
(
$showtype
==
'A'
)
||
(
$showtype
==
'C'
))
&&
isset
(
$showid
))
{
if
(((
$showtype
==
'Q'
)
||
(
$showtype
==
'A'
)
||
(
$showtype
==
'C'
))
&&
isset
(
$showid
))
{
$params
=
array
(
'show'
=>
$showid
);
// due to pagination
$params
=
array
(
'show'
=>
$showid
);
// due to pagination
$anchor
=
qa_anchor
(
$showtype
,
$showid
);
$anchor
=
qa_anchor
(
$showtype
,
$showid
);
}
else
{
}
else
{
$params
=
null
;
$params
=
null
;
$anchor
=
null
;
$anchor
=
null
;
}
}
return
qa_path
(
qa_q_request
(
$questionid
,
$title
),
$params
,
$absolute
?
qa_opt
(
'site_url'
)
:
null
,
null
,
$anchor
);
return
qa_path
(
qa_q_request
(
$questionid
,
$title
),
$params
,
$absolute
?
qa_opt
(
'site_url'
)
:
null
,
null
,
$anchor
);
}
}
/**
/**
* Return the HTML representation of the URL for $questionid - other parameters as for qa_q_path()
* Return the HTML representation of the URL for $questionid - other parameters as for qa_q_path()
*/
*/
function
qa_q_path_html
(
$questionid
,
$title
,
$absolute
=
false
,
$showtype
=
null
,
$showid
=
null
)
function
qa_q_path_html
(
$questionid
,
$title
,
$absolute
=
false
,
$showtype
=
null
,
$showid
=
null
)
{
{
return
qa_html
(
qa_q_path
(
$questionid
,
$title
,
$absolute
,
$showtype
,
$showid
));
return
qa_html
(
qa_q_path
(
$questionid
,
$title
,
$absolute
,
$showtype
,
$showid
));
}
}
/**
/**
* Return the request for the specified $feed
* Return the request for the specified $feed
*/
*/
function
qa_feed_request
(
$feed
)
function
qa_feed_request
(
$feed
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
'feed/'
.
$feed
.
'.rss'
;
return
'feed/'
.
$feed
.
'.rss'
;
}
}
/**
/**
* Return an HTML-ready relative URL for the current page, preserving GET parameters - this is useful for action="..." in HTML forms
* Return an HTML-ready relative URL for the current page, preserving GET parameters - this is useful for action="..." in HTML forms
*/
*/
function
qa_self_html
()
function
qa_self_html
()
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_used_url_format
;
global
$qa_used_url_format
;
return
qa_path_html
(
qa_request
(),
$_GET
,
null
,
$qa_used_url_format
);
return
qa_path_html
(
qa_request
(),
$_GET
,
null
,
$qa_used_url_format
);
}
}
/**
/**
* Return HTML for hidden fields to insert into a <form method="get"...> on the page.
* Return HTML for hidden fields to insert into a <form method="get"...> on the page.
* This is needed because any parameters on the URL will be lost when the form is submitted.
* This is needed because any parameters on the URL will be lost when the form is submitted.
*/
*/
function
qa_path_form_html
(
$request
,
$params
=
null
,
$rooturl
=
null
,
$neaturls
=
null
,
$anchor
=
null
)
function
qa_path_form_html
(
$request
,
$params
=
null
,
$rooturl
=
null
,
$neaturls
=
null
,
$anchor
=
null
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
$path
=
qa_path
(
$request
,
$params
,
$rooturl
,
$neaturls
,
$anchor
);
$path
=
qa_path
(
$request
,
$params
,
$rooturl
,
$neaturls
,
$anchor
);
$formhtml
=
''
;
$formhtml
=
''
;
$questionpos
=
strpos
(
$path
,
'?'
);
$questionpos
=
strpos
(
$path
,
'?'
);
if
(
is_numeric
(
$questionpos
))
{
if
(
is_numeric
(
$questionpos
))
{
$params
=
explode
(
'&'
,
substr
(
$path
,
$questionpos
+
1
));
$params
=
explode
(
'&'
,
substr
(
$path
,
$questionpos
+
1
));
foreach
(
$params
as
$param
)
foreach
(
$params
as
$param
)
if
(
preg_match
(
'/^([^\=]*)(\=(.*))?$/'
,
$param
,
$matches
))
if
(
preg_match
(
'/^([^\=]*)(\=(.*))?$/'
,
$param
,
$matches
))
$formhtml
.=
'<input type="hidden" name="'
.
qa_html
(
urldecode
(
$matches
[
1
]))
.
'" value="'
.
qa_html
(
urldecode
(
@
$matches
[
3
]))
.
'"/>'
;
$formhtml
.=
'<input type="hidden" name="'
.
qa_html
(
urldecode
(
$matches
[
1
]))
.
'" value="'
.
qa_html
(
urldecode
(
@
$matches
[
3
]))
.
'"/>'
;
}
}
return
$formhtml
;
return
$formhtml
;
}
}
/**
/**
* Redirect the user's web browser to $request and then we're done - see qa_path() for other parameters
* Redirect the user's web browser to $request and then we're done - see qa_path() for other parameters
*/
*/
function
qa_redirect
(
$request
,
$params
=
null
,
$rooturl
=
null
,
$neaturls
=
null
,
$anchor
=
null
)
function
qa_redirect
(
$request
,
$params
=
null
,
$rooturl
=
null
,
$neaturls
=
null
,
$anchor
=
null
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
qa_redirect_raw
(
qa_path
(
$request
,
$params
,
$rooturl
,
$neaturls
,
$anchor
));
qa_redirect_raw
(
qa_path
(
$request
,
$params
,
$rooturl
,
$neaturls
,
$anchor
));
}
}
/**
/**
* Redirect the user's web browser to page $path which is already a URL
* Redirect the user's web browser to page $path which is already a URL
*/
*/
function
qa_redirect_raw
(
$url
)
function
qa_redirect_raw
(
$url
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
header
(
'Location: '
.
$url
);
header
(
'Location: '
.
$url
);
qa_exit
(
'redirect'
);
qa_exit
(
'redirect'
);
}
}
// General utilities
// General utilities
/**
/**
* Return the contents of remote $url, using file_get_contents() if possible, otherwise curl functions
* Return the contents of remote $url, using file_get_contents() if possible, otherwise curl functions
*/
*/
function
qa_retrieve_url
(
$url
)
function
qa_retrieve_url
(
$url
)
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
// ensure we're fetching a remote URL
// ensure we're fetching a remote URL
...
@@ -1580,98 +1610,99 @@
...
@@ -1580,98 +1610,99 @@
return
''
;
return
''
;
}
}
$contents
=
@
file_get_contents
(
$url
);
$contents
=
@
file_get_contents
(
$url
);
if
((
!
strlen
(
$contents
))
&&
function_exists
(
'curl_exec'
))
{
// try curl as a backup (if allow_url_fopen not set)
if
((
!
strlen
(
$contents
))
&&
function_exists
(
'curl_exec'
))
{
// try curl as a backup (if allow_url_fopen not set)
$curl
=
curl_init
(
$url
);
$curl
=
curl_init
(
$url
);
curl_setopt
(
$curl
,
CURLOPT_RETURNTRANSFER
,
true
);
curl_setopt
(
$curl
,
CURLOPT_RETURNTRANSFER
,
true
);
curl_setopt
(
$curl
,
CURLOPT_SSL_VERIFYPEER
,
false
);
curl_setopt
(
$curl
,
CURLOPT_SSL_VERIFYPEER
,
false
);
$contents
=
@
curl_exec
(
$curl
);
$contents
=
@
curl_exec
(
$curl
);
curl_close
(
$curl
);
curl_close
(
$curl
);
}
}
return
$contents
;
return
$contents
;
}
}
/**
/**
* Shortcut to get or set an option value without specifying database
* Shortcut to get or set an option value without specifying database
*/
*/
function
qa_opt
(
$name
,
$value
=
null
)
function
qa_opt
(
$name
,
$value
=
null
)
{
{
global
$qa_options_cache
;
global
$qa_options_cache
;
if
((
!
isset
(
$value
))
&&
isset
(
$qa_options_cache
[
$name
]))
if
((
!
isset
(
$value
))
&&
isset
(
$qa_options_cache
[
$name
]))
return
$qa_options_cache
[
$name
];
// quick shortcut to reduce calls to qa_get_options()
return
$qa_options_cache
[
$name
];
// quick shortcut to reduce calls to qa_get_options()
require_once
QA_INCLUDE_DIR
.
'app/options.php'
;
require_once
QA_INCLUDE_DIR
.
'app/options.php'
;
if
(
isset
(
$value
))
if
(
isset
(
$value
))
qa_set_option
(
$name
,
$value
);
qa_set_option
(
$name
,
$value
);
$options
=
qa_get_options
(
array
(
$name
));
$options
=
qa_get_options
(
array
(
$name
));
return
$options
[
$name
];
return
$options
[
$name
];
}
}
/**
/**
* Simple method to output a preformatted variable
* Simple method to output a preformatted variable
*/
*/
function
qa_debug
(
$var
)
function
qa_debug
(
$var
)
{
{
echo
"
\n
"
.
'<pre style="padding: 10px; background-color: #eee; color: #444; font-size: 11px; text-align: left">'
;
echo
"
\n
"
.
'<pre style="padding: 10px; background-color: #eee; color: #444; font-size: 11px; text-align: left">'
;
echo
$var
===
null
?
'NULL'
:
print_r
(
$var
,
true
);
echo
$var
===
null
?
'NULL'
:
print_r
(
$var
,
true
);
echo
'</pre>'
.
"
\n
"
;
echo
'</pre>'
.
"
\n
"
;
}
}
// Event and process stage reporting
// Event and process stage reporting
/**
/**
* Suspend the reporting of events to event modules via qa_report_event(...) if $suspend is
* Suspend the reporting of events to event modules via qa_report_event(...) if $suspend is
* true, otherwise reinstate it. A counter is kept to allow multiple calls.
* true, otherwise reinstate it. A counter is kept to allow multiple calls.
*/
*/
function
qa_suspend_event_reports
(
$suspend
=
true
)
function
qa_suspend_event_reports
(
$suspend
=
true
)
{
{
global
$qa_event_reports_suspended
;
global
$qa_event_reports_suspended
;
$qa_event_reports_suspended
+=
(
$suspend
?
1
:
-
1
);
$qa_event_reports_suspended
+=
(
$suspend
?
1
:
-
1
);
}
}
/**
/**
* Send a notification of event $event by $userid, $handle and $cookieid to all event modules, with extra $params
* Send a notification of event $event by $userid, $handle and $cookieid to all event modules, with extra $params
*/
*/
function
qa_report_event
(
$event
,
$userid
,
$handle
,
$cookieid
,
$params
=
array
())
function
qa_report_event
(
$event
,
$userid
,
$handle
,
$cookieid
,
$params
=
array
())
{
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_event_reports_suspended
;
global
$qa_event_reports_suspended
;
if
(
$qa_event_reports_suspended
>
0
)
if
(
$qa_event_reports_suspended
>
0
)
return
;
return
;
$eventmodules
=
qa_load_modules_with
(
'event'
,
'process_event'
);
$eventmodules
=
qa_load_modules_with
(
'event'
,
'process_event'
);
foreach
(
$eventmodules
as
$eventmodule
)
foreach
(
$eventmodules
as
$eventmodule
)
$eventmodule
->
process_event
(
$event
,
$userid
,
$handle
,
$cookieid
,
$params
);
$eventmodule
->
process_event
(
$event
,
$userid
,
$handle
,
$cookieid
,
$params
);
}
}
function
qa_report_process_stage
(
$method
)
// can have extra params
function
qa_report_process_stage
(
$method
)
// can have extra params
{
{
global
$qa_process_reports_suspended
;
global
$qa_process_reports_suspended
;
if
(
@
$qa_process_reports_suspended
)
if
(
@
$qa_process_reports_suspended
)
return
;
return
;
$qa_process_reports_suspended
=
true
;
// prevent loop, e.g. because of an error
$qa_process_reports_suspended
=
true
;
// prevent loop, e.g. because of an error
$args
=
func_get_args
();
$args
=
func_get_args
();
$args
=
array_slice
(
$args
,
1
);
$args
=
array_slice
(
$args
,
1
);
$processmodules
=
qa_load_modules_with
(
'process'
,
$method
);
$processmodules
=
qa_load_modules_with
(
'process'
,
$method
);
foreach
(
$processmodules
as
$processmodule
)
foreach
(
$processmodules
as
$processmodule
)
{
call_user_func_array
(
array
(
$processmodule
,
$method
),
$args
);
call_user_func_array
(
array
(
$processmodule
,
$method
),
$args
);
$qa_process_reports_suspended
=
null
;
}
}
$qa_process_reports_suspended
=
null
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment