Commit c3681f4f by ProThoughts Committed by GitHub

Merge pull request #6 from q2a/1.8

merge 1.8
parents e0e124c4 e731787d
sudo: false
dist: trusty
language: php
php:
- '5.3'
- '5.4'
- '5.5'
- '5.6'
- '7.0'
- '7.1'
matrix:
include:
- php: '5.3'
dist: precise
notifications:
email:
......@@ -16,16 +23,14 @@ notifications:
before_script:
# PHP_CodeSniffer
- curl -o phpcs.phar https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar
# PHP Copy/Paste Detector
- curl -o phpcpd.phar https://phar.phpunit.de/phpcpd.phar
- curl -L -o phpcs.phar https://github.com/squizlabs/PHP_CodeSniffer/releases/download/2.9.1/phpcs.phar
# PHPUnit - manually download old version so that it works on PHP 7
- curl -L -o phpunit.phar https://phar.phpunit.de/phpunit-4.8.35.phar
# Basic config required for PHPUnit
- cp qa-tests/phpunit-qa-config.php qa-config.php
script:
# PHP_CodeSniffer (turned off for now)
#- php phpcs.phar --report=emacs --extensions=php --standard=qa-tests/phpcs/ruleset.xml .
# PHP Copy/Paste Detector
- php phpcpd.phar --exclude vendor .
# PHP_CodeSniffer
- php phpcs.phar --report=emacs --extensions=php --standard=qa-tests/phpcs/ruleset.xml .
# PHPUnit
- phpunit --bootstrap qa-tests/autoload.php qa-tests
- php phpunit.phar --bootstrap qa-tests/autoload.php qa-tests
......@@ -21,15 +21,11 @@ If you wish to implement a feature, you should start a discussion on the [Questi
## Coding style
From 1.7 onwards a new coding style is being implemented that is more in line with other projects. The core codebase is gradually being refactored, and any new code should use the guidelines below. When making changes it's encouraged to update the style of the surrounding code, e.g. the rest of the function being modified.
However, **please keep style-only changes to a separate commit!** For example if you fix a bug, do that first in one commit, then optionally reformat the rest of the function's code and perform a second commit.
### Guidelines
From 1.7 onwards a new coding style has been implemented that is more in line with other projects. All PHP code should use these guidelines:
- PHP code should start with `<?php` (almost always the very first line). The closing tag `?>` should be omitted to avoid accidental output.
- PHP files should use UTF-8 encoding without BOM (this is usually default in most text editors).
- Trailing whitespace (tabs or spaces at the end of lines) should be trimmed on save. Any advanced text editor should be able to do this. (For Sublime Text you can add the option `"trim_trailing_white_space_on_save": true` to your preferences. In Notepad++ you can press Alt+Shift+S.)
- Trailing whitespace (tabs or spaces at the end of lines) should not be present. Any advanced text editor should be able to do this automatically when saving. (For Sublime Text you can add the option `"trim_trailing_white_space_on_save": true` to your preferences. In Notepad++ you can press Alt+Shift+S.)
- Use tabs for indenting. Each file should start at level 0 (i.e. no indentation).
- Functions should use a DocBlock-style comment.
- Operators (`=`, `+` etc) should have a space either side.
......@@ -37,66 +33,12 @@ However, **please keep style-only changes to a separate commit!** For example if
- Opening braces for classes and functions should be on the next line.
- Opening braces for control structures should be on the same line. All control structures should use braces.
### Examples
Here is an example of the old style. Even though the braces are technically optional (the foreach contains only one statement), they should be used here for clarity.
foreach ($thingarray as $thing)
if (isset($thing['id']))
if (strpos($thing['id'], 'Hello')===0)
$newthing='Goodbye';
elseif ($thing['id']=='World')
$newerthing='Galaxy';
else
return null;
It should be rewritten as:
foreach ($thingarray as $thing) {
if (isset($thing['id'])) {
if (strpos($thing['id'], 'Hello') === 0) {
$newthing = 'Goodbye';
} elseif ($thing['id'] == 'World') {
$newerthing = 'Galaxy';
}
} else {
return null;
}
}
Here is a class example showing the placement of braces, operators, and a DocBlock comment.
class qa_example
{
/**
* Adds 1 to the supplied number.
*
* @param int $number The number to increment.
*
* @return int Returns the new number.
*/
public function add_one($number)
{
$result = $number + 1;
return $result;
}
}
### New autoloaded classes
From version 1.7 some classes are autoloaded, so it's possible to use them without adding a `require_once` first. These loosely follow [PSR-0][PSR0] using faux namespaces. This is being done slowly and carefully to maintain backwards compatibility, and does not apply to plugins, themes, nor most of the core for that matter.
Classes are stored in the `qa-include/Q2A` folder, and then in subfolders depending on their categorization.
Class names should be of the form `Q2A_<Namespace>_<Class>`, e.g. `Q2A_Util_Debug`. There may be multiple "namespaces", e.g. `Q2A_Db_User_Messages`.
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`.
If in doubt, follow the style of the surrounding code. Code examples can be found in the [Q2A docs here](http://docs.question2answer.org/contribute/).
## Documentation
Please see the repository https://github.com/q2a/q2a.github.io/ which automatically produces the documentation website http://docs.question2answer.org/
Please see the repository [q2a.github.io](https://github.com/q2a/q2a.github.io/) which automatically produces the documentation website [docs.question2answer.org](http://docs.question2answer.org/).
[Home]: http://www.question2answer.org/
......
Question2Answer
-----------------------------
[![Build Status](https://travis-ci.org/q2a/question2answer.png?branch=master)](https://travis-ci.org/q2a/question2answer)
[![Build Status](https://travis-ci.org/q2a/question2answer.png?branch=1.8)](https://travis-ci.org/q2a/question2answer/branches)
[Question2Answer][Q2A] (Q2A) is a popular free open source Q&A platform for PHP/MySQL, used by over 16,000 sites in 40 languages.
[Question2Answer][Q2A] (Q2A) is a popular free open source Q&A platform for PHP/MySQL, used by over 20,898 [sites] in 40 languages.
Q2A is highly customisable with many awesome features:
......@@ -22,6 +22,7 @@ Q2A is highly customisable with many awesome features:
- Private messages and public wall posts.
- Log in via Facebook or others (using plugins).
- Out-of-the-box WordPress 3+ integration.
- Out-of-the-box Joomla! 3.0+ integration (in conjunction with a Joomla! extension).
- Custom single sign-on support for other sites.
- PHP/MySQL scalable to millions of users and posts.
- Safe from XSS, CSRF and SQL injection attacks.
......@@ -58,3 +59,4 @@ Gideon
[Q2A]: http://www.question2answer.org/
[1]: http://www.question2answer.org/qa/user/Scott
[2]: https://github.com/q2a/question2answer/blob/master/CONTRIBUTING.md
[sites]: http://www.question2answer.org/sites.php
1.7.4
\ No newline at end of file
1.8.0-beta1
\ No newline at end of file
......@@ -20,13 +20,8 @@
More about this license: http://www.question2answer.org/license.php
*/
// Set base path here so this works with symbolic links for multiple installations
// Set base path here so this works with symbolic links for multiple installations
define('QA_BASE_DIR', dirname(empty($_SERVER['SCRIPT_FILENAME']) ? __FILE__ : $_SERVER['SCRIPT_FILENAME']).'/');
define('QA_BASE_DIR', dirname(empty($_SERVER['SCRIPT_FILENAME']) ? __FILE__ : $_SERVER['SCRIPT_FILENAME']) . '/');
require 'qa-include/qa-index.php';
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
require 'qa-include/qa-index.php';
......@@ -86,6 +86,15 @@
*/
/*
If you wish to use caching, you must define QA_CACHE_DIRECTORY to store the cache files. The
directory must be writable by the web server. It also must be OUTSIDE the public root. For
example if your site resides in '/var/www/yoursite/public_html', then the cache directory could
be '/var/www/yoursite/qa-cache', but it cannot be '/var/www/yoursite/public_html/qa-cache'.
define('QA_CACHE_DIRECTORY', '/path/to/writable_cache_directory/');
*/
/*
If you wish, you can define QA_COOKIE_DOMAIN so that any cookies created by Q2A are assigned
to a specific domain name, instead of the full domain name of the request by default. This is
useful if you're running multiple Q2A sites on subdomains with a shared user base.
......@@ -99,7 +108,7 @@
and the value should be the replacement for that standard part, e.g. 'topics'. If you edit this
file in UTF-8 encoding you can also use non-ASCII characters in these URLs.
$QA_CONST_PATH_MAP=array(
$QA_CONST_PATH_MAP = array(
'questions' => 'topics',
'categories' => 'sections',
'users' => 'contributors',
......@@ -128,6 +137,17 @@
*/
/*
Out-of-the-box Joomla! 3.x integration - to integrate with your Joomla! site, define
QA_JOOMLA_INTEGRATE_PATH. as the full path to the Joomla! directory. If your Q2A
site is a subdirectory of your main Joomla site (recommended), you can specify
dirname(__DIR__) rather than the full path.
With this set, you do not need to set the QA_MYSQL_* constants above since these
will be taken from Joomla automatically. See online documentation for more details.
define('QA_JOOMLA_INTEGRATE_PATH', dirname(__DIR__));
*/
/*
Some settings to help optimize your Question2Answer site's performance.
If QA_HTML_COMPRESSION is true, HTML web pages will be output using Gzip compression, if
......@@ -147,13 +167,14 @@
are not indexed efficiently. For example, this will enable browsing unanswered questions per
category. If your database becomes large, these queries could become costly.
Set QA_OPTIMIZE_LOCAL_DB to true if your web server and MySQL are running on the same box.
Set QA_OPTIMIZE_DISTANT_DB to false if your web server and MySQL are running on the same box.
When viewing a page on your site, this will use many simple MySQL queries instead of fewer
complex ones, which makes sense since there is no latency for localhost access.
Otherwise, set it to true if your web server and MySQL are far enough apart to create
significant latency. This will minimize the number of database queries as much as is possible,
even at the cost of significant additional processing at each end.
Set QA_OPTIMIZE_DISTANT_DB to true if your web server and MySQL are far enough apart to
create significant latency. This will minimize the number of database queries as much as
is possible, even at the cost of significant additional processing at each end.
The option QA_OPTIMIZE_LOCAL_DB is no longer used, since QA_OPTIMIZE_DISTANT_DB covers our uses.
Set QA_PERSISTENT_CONN_DB to true to use persistent database connections. Requires PHP 5.3.
Only use this if you are absolutely sure it is a good idea under your setup - generally it is
......@@ -167,7 +188,6 @@
define('QA_MAX_LIMIT_START', 19999);
define('QA_IGNORED_WORDS_FREQ', 10000);
define('QA_ALLOW_UNINDEXED_QUERIES', false);
define('QA_OPTIMIZE_LOCAL_DB', false);
define('QA_OPTIMIZE_DISTANT_DB', false);
define('QA_PERSISTENT_CONN_DB', false);
define('QA_DEBUG_PERFORMANCE', false);
......@@ -176,8 +196,3 @@
And lastly... if you want to, you can predefine any constant from qa-db-maxima.php in this
file to override the default setting. Just make sure you know what you're doing!
*/
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-content/qa-admin.js
Version: See define()s at top of qa-include/qa-base.php
Description: Javascript for admin pages to handle Ajax-triggered operations
......@@ -22,14 +19,14 @@
More about this license: http://www.question2answer.org/license.php
*/
var qa_recalc_running=0;
var qa_recalc_running = 0;
window.onbeforeunload=function(event)
window.onbeforeunload = function(event)
{
if (qa_recalc_running>0) {
event=event||window.event;
var message=qa_warning_recalc;
event.returnValue=message;
if (qa_recalc_running > 0) {
event = event || window.event;
var message = qa_warning_recalc;
event.returnValue = message;
return message;
}
};
......@@ -37,17 +34,17 @@ window.onbeforeunload=function(event)
function qa_recalc_click(state, elem, value, noteid)
{
if (elem.qa_recalc_running) {
elem.qa_recalc_stopped=true;
elem.qa_recalc_stopped = true;
} else {
elem.qa_recalc_running=true;
elem.qa_recalc_stopped=false;
elem.qa_recalc_running = true;
elem.qa_recalc_stopped = false;
qa_recalc_running++;
document.getElementById(noteid).innerHTML='';
elem.qa_original_value=elem.value;
document.getElementById(noteid).innerHTML = '';
elem.qa_original_value = elem.value;
if (value)
elem.value=value;
elem.value = value;
qa_recalc_update(elem, state, noteid);
}
......@@ -57,20 +54,23 @@ function qa_recalc_click(state, elem, value, noteid)
function qa_recalc_update(elem, state, noteid)
{
if (state)
qa_ajax_post('recalc', {state:state, code:(elem.form.elements.code_recalc ? elem.form.elements.code_recalc.value : elem.form.elements.code.value)},
if (state) {
var recalcCode = elem.form.elements.code_recalc ? elem.form.elements.code_recalc.value : elem.form.elements.code.value;
qa_ajax_post(
'recalc',
{state: state, code: recalcCode},
function(lines) {
if (lines[0]=='1') {
if (lines[0] == '1') {
if (lines[2])
document.getElementById(noteid).innerHTML=lines[2];
document.getElementById(noteid).innerHTML = lines[2];
if (elem.qa_recalc_stopped)
qa_recalc_cleanup(elem);
else
qa_recalc_update(elem, lines[1], noteid);
} else if (lines[0]=='0') {
document.getElementById(noteid).innerHTML=lines[1];
} else if (lines[0] == '0') {
document.getElementById(noteid).innerHTML = lines[1];
qa_recalc_cleanup(elem);
} else {
......@@ -79,29 +79,31 @@ function qa_recalc_update(elem, state, noteid)
}
}
);
else
} else {
qa_recalc_cleanup(elem);
}
}
function qa_recalc_cleanup(elem)
{
elem.value=elem.qa_original_value;
elem.qa_recalc_running=null;
elem.value = elem.qa_original_value;
elem.qa_recalc_running = null;
qa_recalc_running--;
}
function qa_mailing_start(noteid, pauseid)
{
qa_ajax_post('mailing', {},
function (lines) {
if (lines[0]=='1') {
document.getElementById(noteid).innerHTML=lines[1];
window.setTimeout(function() { qa_mailing_start(noteid, pauseid); }, 1); // don't recurse
function(lines) {
if (lines[0] == '1') {
document.getElementById(noteid).innerHTML = lines[1];
window.setTimeout(function() {
qa_mailing_start(noteid, pauseid);
}, 1); // don't recurse
} else if (lines[0]=='0') {
document.getElementById(noteid).innerHTML=lines[1];
document.getElementById(pauseid).style.display='none';
} else if (lines[0] == '0') {
document.getElementById(noteid).innerHTML = lines[1];
document.getElementById(pauseid).style.display = 'none';
} else {
qa_ajax_error();
......@@ -112,16 +114,16 @@ function qa_mailing_start(noteid, pauseid)
function qa_admin_click(target)
{
var p=target.name.split('_');
var p = target.name.split('_');
var params={entityid:p[1], action:p[2]};
params.code=target.form.elements.code.value;
var params = {entityid: p[1], action: p[2]};
params.code = target.form.elements.code.value;
qa_ajax_post('click_admin', params,
function (lines) {
if (lines[0]=='1')
qa_conceal(document.getElementById('p'+p[1]), 'admin');
else if (lines[0]=='0') {
function(lines) {
if (lines[0] == '1')
qa_conceal(document.getElementById('p' + p[1]), 'admin');
else if (lines[0] == '0') {
alert(lines[1]);
qa_hide_waiting(target);
} else
......@@ -134,14 +136,26 @@ function qa_admin_click(target)
return false;
}
function qa_version_check(uri, version, elem)
function qa_version_check(uri, version, elem, isCore)
{
var params={uri:uri, version:version};
var params = {uri: uri, version: version, isCore: isCore};
qa_ajax_post('version', params,
function (lines) {
if (lines[0]=='1')
document.getElementById(elem).innerHTML=lines[1];
function(lines) {
if (lines[0] == '1')
document.getElementById(elem).innerHTML = lines[1];
}
);
}
function qa_get_enabled_plugins_hashes()
{
var hashes = [];
$('[id^=plugin_enabled]:checked').each(
function(idx, elem) {
hashes.push(elem.id.replace("plugin_enabled_", ""));
}
);
$('[name=enabled_plugins_hashes]').val(hashes.join(';'));
}
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-content/qa-page.js
Version: See define()s at top of qa-include/qa-base.php
Description: Common Javascript including voting, notices and favorites
Description: THIS FILE HAS BEEN DEPRECATED IN FAVOUR OF qa-global.js
This program is free software; you can redistribute it and/or
......@@ -37,14 +34,14 @@ function qa_conceal(elem, type, callback)
function qa_set_inner_html(elem, type, html)
{
if (elem)
elem.innerHTML=html;
elem.innerHTML = html;
}
function qa_set_outer_html(elem, type, html)
{
if (elem) {
var e=document.createElement('div');
e.innerHTML=html;
var e = document.createElement('div');
e.innerHTML = html;
elem.parentNode.replaceChild(e.firstChild, elem);
}
}
......@@ -52,58 +49,58 @@ function qa_set_outer_html(elem, type, html)
function qa_show_waiting_after(elem, inside)
{
if (elem && !elem.qa_waiting_shown) {
var w=document.getElementById('qa-waiting-template');
var w = document.getElementById('qa-waiting-template');
if (w) {
var c=w.cloneNode(true);
c.id=null;
var c = w.cloneNode(true);
c.id = null;
if (inside)
elem.insertBefore(c, null);
else
elem.parentNode.insertBefore(c, elem.nextSibling);
elem.qa_waiting_shown=c;
elem.qa_waiting_shown = c;
}
}
}
function qa_hide_waiting(elem)
{
var c=elem.qa_waiting_shown;
var c = elem.qa_waiting_shown;
if (c) {
c.parentNode.removeChild(c);
elem.qa_waiting_shown=null;
elem.qa_waiting_shown = null;
}
}
function qa_vote_click(elem)
{
var ens=elem.name.split('_');
var postid=ens[1];
var vote=parseInt(ens[2]);
var code=elem.form.elements.code.value;
var anchor=ens[3];
var ens = elem.name.split('_');
var postid = ens[1];
var vote = parseInt(ens[2]);
var code = elem.form.elements.code.value;
var anchor = ens[3];
qa_ajax_post('vote', {postid:postid, vote:vote, code:code},
qa_ajax_post('vote', {postid: postid, vote: vote, code: code},
function(lines) {
if (lines[0]=='1') {
qa_set_inner_html(document.getElementById('voting_'+postid), 'voting', lines.slice(1).join("\n"));
if (lines[0] == '1') {
qa_set_inner_html(document.getElementById('voting_' + postid), 'voting', lines.slice(1).join("\n"));
} else if (lines[0]=='0') {
var mess=document.getElementById('errorbox');
} else if (lines[0] == '0') {
var mess = document.getElementById('errorbox');
if (!mess) {
var mess=document.createElement('div');
mess.id='errorbox';
mess.className='qa-error';
mess.innerHTML=lines[1];
mess.style.display='none';
var mess = document.createElement('div');
mess.id = 'errorbox';
mess.className = 'qa-error';
mess.innerHTML = lines[1];
mess.style.display = 'none';
}
var postelem=document.getElementById(anchor);
var e=postelem.parentNode.insertBefore(mess, postelem);
var postelem = document.getElementById(anchor);
var e = postelem.parentNode.insertBefore(mess, postelem);
qa_reveal(e);
} else
......@@ -116,14 +113,14 @@ function qa_vote_click(elem)
function qa_notice_click(elem)
{
var ens=elem.name.split('_');
var code=elem.form.elements.code.value;
var ens = elem.name.split('_');
var code = elem.form.elements.code.value;
qa_ajax_post('notice', {noticeid:ens[1], code:code},
qa_ajax_post('notice', {noticeid: ens[1], code: code},
function(lines) {
if (lines[0]=='1')
qa_conceal(document.getElementById('notice_'+ens[1]), 'notice');
else if (lines[0]=='0')
if (lines[0] == '1')
qa_conceal(document.getElementById('notice_' + ens[1]), 'notice');
else if (lines[0] == '0')
alert(lines[1]);
else
qa_ajax_error();
......@@ -135,14 +132,14 @@ function qa_notice_click(elem)
function qa_favorite_click(elem)
{
var ens=elem.name.split('_');
var code=elem.form.elements.code.value;
var ens = elem.name.split('_');
var code = elem.form.elements.code.value;
qa_ajax_post('favorite', {entitytype:ens[1], entityid:ens[2], favorite:parseInt(ens[3]), code:code},
function (lines) {
if (lines[0]=='1')
qa_ajax_post('favorite', {entitytype: ens[1], entityid: ens[2], favorite: parseInt(ens[3]), code: code},
function(lines) {
if (lines[0] == '1')
qa_set_inner_html(document.getElementById('favoriting'), 'favoriting', lines.slice(1).join("\n"));
else if (lines[0]=='0') {
else if (lines[0] == '0') {
alert(lines[1]);
qa_hide_waiting(elem);
} else
......@@ -157,21 +154,37 @@ function qa_favorite_click(elem)
function qa_ajax_post(operation, params, callback)
{
jQuery.extend(params, {qa:'ajax', qa_operation:operation, qa_root:qa_root, qa_request:qa_request});
$.extend(params, {qa: 'ajax', qa_operation: operation, qa_root: qa_root, qa_request: qa_request});
jQuery.post(qa_root, params, function(response) {
var header='QA_AJAX_RESPONSE';
var headerpos=response.indexOf(header);
$.post(qa_root, params, function(response) {
var header = 'QA_AJAX_RESPONSE';
var headerpos = response.indexOf(header);
if (headerpos>=0)
callback(response.substr(headerpos+header.length).replace(/^\s+/, '').split("\n"));
if (headerpos >= 0)
callback(response.substr(headerpos + header.length).replace(/^\s+/, '').split("\n"));
else
callback([]);
}, 'text').fail(function(jqXHR) { if (jqXHR.readyState>0) callback([]) });
}, 'text').fail(function(jqXHR) {
if (jqXHR.readyState > 0)
callback([])
});
}
function qa_ajax_error()
{
alert('Unexpected response from server - please try again or switch off Javascript.');
}
function qa_display_rule_show(target, show, first)
{
var e = document.getElementById(target);
if (e) {
if (first || e.nodeName == 'SPAN')
e.style.display = (show ? '' : 'none');
else if (show)
$(e).fadeIn();
else
$(e).fadeOut();
}
}
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-content/qa-question.js
Version: See define()s at top of qa-include/qa-base.php
Description: Javascript to handle question page actions
Description: THIS FILE HAS BEEN DEPRECATED IN FAVOUR OF qa-global.js
This program is free software; you can redistribute it and/or
......@@ -22,18 +19,18 @@
More about this license: http://www.question2answer.org/license.php
*/
var qa_element_revealed=null;
var qa_element_revealed = null;
function qa_toggle_element(elem)
{
var e=elem ? document.getElementById(elem) : null;
var e = elem ? document.getElementById(elem) : null;
if (e && e.qa_disabled)
e=null;
e = null;
if (e && (qa_element_revealed==e)) {
if (e && (qa_element_revealed == e)) {
qa_conceal(qa_element_revealed, 'form');
qa_element_revealed=null;
qa_element_revealed = null;
} else {
if (qa_element_revealed)
......@@ -42,76 +39,74 @@ function qa_toggle_element(elem)
if (e) {
if (e.qa_load && !e.qa_loaded) {
e.qa_load();
e.qa_loaded=true;
e.qa_loaded = true;
}
if (e.qa_show)
e.qa_show();
qa_reveal(e, 'form', function() {
var t=$(e).offset().top;
var h=$(e).height()+16;
var wt=$(window).scrollTop();
var wh=$(window).height();
var t = $(e).offset().top;
var h = $(e).height() + 16;
var wt = $(window).scrollTop();
var wh = $(window).height();
if ( (t<wt) || (t>(wt+wh)) )
if ((t < wt) || (t > (wt + wh)))
qa_scroll_page_to(t);
else if ((t+h)>(wt+wh))
qa_scroll_page_to(t+h-wh);
else if ((t + h) > (wt + wh))
qa_scroll_page_to(t + h - wh);
if (e.qa_focus)
e.qa_focus();
});
}
qa_element_revealed=e;
qa_element_revealed = e;
}
return !(e||!elem); // failed to find item
return !(e || !elem); // failed to find item
}
function qa_submit_answer(questionid, elem)
{
var params=qa_form_params('a_form');
var params = qa_form_params('a_form');
params.a_questionid=questionid;
params.a_questionid = questionid;
qa_ajax_post('answer', params,
function(lines) {
if (lines[0]=='1') {
if (lines[1]<1) {
var b=document.getElementById('q_doanswer');
if (lines[0] == '1') {
if (lines[1] < 1) {
var b = document.getElementById('q_doanswer');
if (b)
b.style.display='none';
b.style.display = 'none';
}
var t=document.getElementById('a_list_title');
var t = document.getElementById('a_list_title');
qa_set_inner_html(t, 'a_list_title', lines[2]);
qa_reveal(t, 'a_list_title');
var e=document.createElement('div');
e.innerHTML=lines.slice(3).join("\n");
var e = document.createElement('div');
e.innerHTML = lines.slice(3).join("\n");
var c=e.firstChild;
c.style.display='none';
var c = e.firstChild;
c.style.display = 'none';
var l=document.getElementById('a_list');
var l = document.getElementById('a_list');
l.insertBefore(c, l.firstChild);
var a=document.getElementById('anew');
a.qa_disabled=true;
var a = document.getElementById('anew');
a.qa_disabled = true;
qa_reveal(c, 'answer');
qa_conceal(a, 'form');
} else if (lines[0]=='0') {
} else if (lines[0] == '0') {
document.forms['a_form'].submit();
} else {
qa_ajax_error();
}
}
);
......@@ -122,32 +117,32 @@ function qa_submit_answer(questionid, elem)
function qa_submit_comment(questionid, parentid, elem)
{
var params=qa_form_params('c_form_'+parentid);
var params = qa_form_params('c_form_' + parentid);
params.c_questionid=questionid;
params.c_parentid=parentid;
params.c_questionid = questionid;
params.c_parentid = parentid;
qa_ajax_post('comment', params,
function (lines) {
function(lines) {
if (lines[0]=='1') {
var l=document.getElementById('c'+parentid+'_list');
l.innerHTML=lines.slice(2).join("\n");
l.style.display='';
if (lines[0] == '1') {
var l = document.getElementById('c' + parentid + '_list');
l.innerHTML = lines.slice(2).join("\n");
l.style.display = '';
var a=document.getElementById('c'+parentid);
a.qa_disabled=true;
var a = document.getElementById('c' + parentid);
a.qa_disabled = true;
var c=document.getElementById(lines[1]); // id of comment
var c = document.getElementById(lines[1]); // id of comment
if (c) {
c.style.display='none';
c.style.display = 'none';
qa_reveal(c, 'comment');
}
qa_conceal(a, 'form');
} else if (lines[0]=='0') {
document.forms['c_form_'+parentid].submit();
} else if (lines[0] == '0') {
document.forms['c_form_' + parentid].submit();
} else {
qa_ajax_error();
......@@ -163,20 +158,20 @@ function qa_submit_comment(questionid, parentid, elem)
function qa_answer_click(answerid, questionid, target)
{
var params={};
var params = {};
params.answerid=answerid;
params.questionid=questionid;
params.code=target.form.elements.code.value;
params[target.name]=target.value;
params.answerid = answerid;
params.questionid = questionid;
params.code = target.form.elements.code.value;
params[target.name] = target.value;
qa_ajax_post('click_a', params,
function (lines) {
if (lines[0]=='1') {
function(lines) {
if (lines[0] == '1') {
qa_set_inner_html(document.getElementById('a_list_title'), 'a_list_title', lines[1]);
var l=document.getElementById('a'+answerid);
var h=lines.slice(2).join("\n");
var l = document.getElementById('a' + answerid);
var h = lines.slice(2).join("\n");
if (h.length)
qa_set_outer_html(l, 'answer', h);
......@@ -184,7 +179,7 @@ function qa_answer_click(answerid, questionid, target)
qa_conceal(l, 'answer');
} else {
target.form.elements.qa_click.value=target.name;
target.form.elements.qa_click.value = target.name;
target.form.submit();
}
}
......@@ -197,27 +192,27 @@ function qa_answer_click(answerid, questionid, target)
function qa_comment_click(commentid, questionid, parentid, target)
{
var params={};
var params = {};
params.commentid=commentid;
params.questionid=questionid;
params.parentid=parentid;
params.code=target.form.elements.code.value;
params[target.name]=target.value;
params.commentid = commentid;
params.questionid = questionid;
params.parentid = parentid;
params.code = target.form.elements.code.value;
params[target.name] = target.value;
qa_ajax_post('click_c', params,
function (lines) {
if (lines[0]=='1') {
var l=document.getElementById('c'+commentid);
var h=lines.slice(1).join("\n");
function(lines) {
if (lines[0] == '1') {
var l = document.getElementById('c' + commentid);
var h = lines.slice(1).join("\n");
if (h.length)
qa_set_outer_html(l, 'comment', h)
qa_set_outer_html(l, 'comment', h);
else
qa_conceal(l, 'comment');
} else {
target.form.elements.qa_click.value=target.name;
target.form.elements.qa_click.value = target.name;
target.form.submit();
}
}
......@@ -230,17 +225,17 @@ function qa_comment_click(commentid, questionid, parentid, target)
function qa_show_comments(questionid, parentid, elem)
{
var params={};
var params = {};
params.c_questionid=questionid;
params.c_parentid=parentid;
params.c_questionid = questionid;
params.c_parentid = parentid;
qa_ajax_post('show_cs', params,
function (lines) {
if (lines[0]=='1') {
var l=document.getElementById('c'+parentid+'_list');
l.innerHTML=lines.slice(1).join("\n");
l.style.display='none';
function(lines) {
if (lines[0] == '1') {
var l = document.getElementById('c' + parentid + '_list');
l.innerHTML = lines.slice(1).join("\n");
l.style.display = 'none';
qa_reveal(l, 'comments');
} else {
......@@ -256,15 +251,15 @@ function qa_show_comments(questionid, parentid, elem)
function qa_form_params(formname)
{
var es=document.forms[formname].elements;
var params={};
var es = document.forms[formname].elements;
var params = {};
for (var i=0; i<es.length; i++) {
var e=es[i];
var t=(e.type || '').toLowerCase();
for (var i = 0; i < es.length; i++) {
var e = es[i];
var t = (e.type || '').toLowerCase();
if ( ((t!='checkbox') && (t!='radio')) || e.checked)
params[e.name]=e.value;
if (((t != 'checkbox') && (t != 'radio')) || e.checked)
params[e.name] = e.value;
}
return params;
......
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-content/qa-user.js
Version: See define()s at top of qa-include/qa-base.php
Description: Javascript to handle user page actions
Description: THIS FILE HAS BEEN DEPRECATED IN FAVOUR OF qa-global.js
This program is free software; you can redistribute it and/or
......@@ -24,32 +21,31 @@
function qa_submit_wall_post(elem, morelink)
{
var params={};
var params = {};
params.message=document.forms.wallpost.message.value;
params.handle=document.forms.wallpost.handle.value;
params.start=document.forms.wallpost.start.value;
params.code=document.forms.wallpost.code.value;
params.morelink=morelink ? 1 : 0;
params.message = document.forms.wallpost.message.value;
params.handle = document.forms.wallpost.handle.value;
params.start = document.forms.wallpost.start.value;
params.code = document.forms.wallpost.code.value;
params.morelink = morelink ? 1 : 0;
qa_ajax_post('wallpost', params,
function(lines) {
if (lines[0] == '1') {
var l = document.getElementById('wallmessages');
l.innerHTML = lines.slice(2).join("\n");
if (lines[0]=='1') {
var l=document.getElementById('wallmessages');
l.innerHTML=lines.slice(2).join("\n");
var c=document.getElementById(lines[1]); // id of new message
var c = document.getElementById(lines[1]); // id of new message
if (c) {
c.style.display='none';
c.style.display = 'none';
qa_reveal(c, 'wallpost');
}
document.forms.wallpost.message.value='';
document.forms.wallpost.message.value = '';
qa_hide_waiting(elem);
} else if (lines[0]=='0') {
document.forms.wallpost.qa_click.value=elem.name;
} else if (lines[0] == '0') {
document.forms.wallpost.qa_click.value = elem.name;
document.forms.wallpost.submit();
} else {
......@@ -63,31 +59,30 @@ function qa_submit_wall_post(elem, morelink)
return false;
}
function qa_wall_post_click(messageid, target)
{
var params={};
var params = {};
params.messageid=messageid;
params.handle=document.forms.wallpost.handle.value;
params.start=document.forms.wallpost.start.value;
params.code=document.forms.wallpost.code.value;
params.messageid = messageid;
params.handle = document.forms.wallpost.handle.value;
params.start = document.forms.wallpost.start.value;
params.code = document.forms.wallpost.code.value;
params[target.name]=target.value;
params[target.name] = target.value;
qa_ajax_post('click_wall', params,
function (lines) {
if (lines[0]=='1') {
var l=document.getElementById('m'+messageid);
var h=lines.slice(1).join("\n");
function(lines) {
if (lines[0] == '1') {
var l = document.getElementById('m' + messageid);
var h = lines.slice(1).join("\n");
if (h.length)
qa_set_outer_html(l, 'wallpost', h)
qa_set_outer_html(l, 'wallpost', h);
else
qa_conceal(l, 'wallpost');
} else {
document.forms.wallpost.qa_click.value=target.name;
document.forms.wallpost.qa_click.value = target.name;
document.forms.wallpost.submit();
}
}
......@@ -98,7 +93,6 @@ function qa_wall_post_click(messageid, target)
return false;
}
function qa_pm_click(messageid, target, box)
{
var params = {};
......@@ -112,13 +106,13 @@ function qa_pm_click(messageid, target, box)
params[target.name] = target.value;
qa_ajax_post('click_pm', params,
function (lines) {
if (lines[0]=='1') {
var l = document.getElementById('m'+messageid);
function(lines) {
if (lines[0] == '1') {
var l = document.getElementById('m' + messageid);
var h = lines.slice(1).join("\n");
if (h.length)
qa_set_outer_html(l, 'pmessage', h)
qa_set_outer_html(l, 'pmessage', h);
else
qa_conceal(l, 'pmessage');
......
......@@ -48,7 +48,7 @@ if (!defined('QA_VERSION')) { // don't allow this page to be requested directly
*/
function qa_get_mysql_user_column_type()
{
// Set this before anything else
// Set this before anything else
return null;
......@@ -101,7 +101,7 @@ function qa_get_mysql_user_column_type()
*/
function qa_get_login_links($relative_url_prefix, $redirect_back_to_url)
{
// Until you edit this function, don't show login, register or logout links
// Until you edit this function, don't show login, register or logout links
return array(
'login' => null,
......@@ -187,7 +187,7 @@ function qa_get_login_links($relative_url_prefix, $redirect_back_to_url)
*/
function qa_get_logged_in_user()
{
// Until you edit this function, nobody is ever logged in
// Until you edit this function, nobody is ever logged in
return null;
......@@ -267,7 +267,7 @@ function qa_get_logged_in_user()
*/
function qa_get_user_email($userid)
{
// Until you edit this function, always return null
// Until you edit this function, always return null
return null;
......@@ -308,7 +308,7 @@ function qa_get_user_email($userid)
*/
function qa_get_userids_from_public($publicusernames)
{
// Until you edit this function, always return null
// Until you edit this function, always return null
return null;
......@@ -371,7 +371,7 @@ function qa_get_userids_from_public($publicusernames)
*/
function qa_get_public_from_userids($userids)
{
// Until you edit this function, always return null
// Until you edit this function, always return null
return null;
......@@ -440,7 +440,7 @@ function qa_get_public_from_userids($userids)
*/
function qa_get_logged_in_user_html($logged_in_user, $relative_url_prefix)
{
// By default, show the public username linked to the Q2A profile page for the user
// By default, show the public username linked to the Q2A profile page for the user
$publicusername = $logged_in_user['publicusername'];
......@@ -502,7 +502,7 @@ function qa_get_logged_in_user_html($logged_in_user, $relative_url_prefix)
*/
function qa_get_users_html($userids, $should_include_link, $relative_url_prefix)
{
// By default, show the public username linked to the Q2A profile page for each user
// By default, show the public username linked to the Q2A profile page for each user
$useridtopublic = qa_get_public_from_userids($userids);
......
<?php
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/Q2A/Plugin/PluginManager.php
Description: Keeps track of the installed plugins
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
class Q2A_Plugin_PluginManager
{
const PLUGIN_DELIMITER = ';';
const OPT_ENABLED_PLUGINS = 'enabled_plugins';
private $loadBeforeDbInit = array();
private $loadAfterDbInit = array();
public function readAllPluginMetadatas()
{
$pluginDirectories = $this->getFilesystemPlugins(true);
foreach ($pluginDirectories as $pluginDirectory) {
$pluginFile = $pluginDirectory . 'qa-plugin.php';
if (!file_exists($pluginFile)) {
continue;
}
$metadataUtil = new Q2A_Util_Metadata();
$metadata = $metadataUtil->fetchFromAddonPath($pluginDirectory);
if (empty($metadata)) {
// limit plugin parsing to first 8kB
$contents = file_get_contents($pluginFile, false, null, 0, 8192);
$metadata = qa_addon_metadata($contents, 'Plugin', true);
}
// skip plugin which requires a later version of Q2A
if (isset($metadata['min_q2a']) && qa_qa_version_below($metadata['min_q2a'])) {
continue;
}
// skip plugin which requires a later version of PHP
if (isset($metadata['min_php']) && qa_php_version_below($metadata['min_php'])) {
continue;
}
$pluginInfoKey = basename($pluginDirectory);
$pluginInfo = array(
'pluginfile' => $pluginFile,
'directory' => $pluginDirectory,
'urltoroot' => substr($pluginDirectory, strlen(QA_BASE_DIR)),
);
if (isset($metadata['load_order'])) {
switch ($metadata['load_order']) {
case 'after_db_init':
$this->loadAfterDbInit[$pluginInfoKey] = $pluginInfo;
break;
case 'before_db_init':
$this->loadBeforeDbInit[$pluginInfoKey] = $pluginInfo;
break;
default:
}
} else {
$this->loadBeforeDbInit[$pluginInfoKey] = $pluginInfo;
}
}
}
private function loadPlugins($pluginInfos)
{
global $qa_plugin_directory, $qa_plugin_urltoroot;
foreach ($pluginInfos as $pluginInfo) {
$qa_plugin_directory = $pluginInfo['directory'];
$qa_plugin_urltoroot = $pluginInfo['urltoroot'];
require_once $pluginInfo['pluginfile'];
}
$qa_plugin_directory = null;
$qa_plugin_urltoroot = null;
}
public function loadPluginsBeforeDbInit()
{
$this->loadPlugins($this->loadBeforeDbInit);
}
public function loadPluginsAfterDbInit()
{
$enabledPlugins = $this->getEnabledPlugins(false);
$enabledForAfterDbInit = array();
foreach ($enabledPlugins as $enabledPluginDirectory) {
if (isset($this->loadAfterDbInit[$enabledPluginDirectory])) {
$enabledForAfterDbInit[$enabledPluginDirectory] = $this->loadAfterDbInit[$enabledPluginDirectory];
}
}
$this->loadPlugins($enabledForAfterDbInit);
}
public function getEnabledPlugins($fullPath = false)
{
$pluginDirectories = $this->getEnabledPluginsOption();
if ($fullPath) {
foreach ($pluginDirectories as $key => &$pluginDirectory) {
$pluginDirectory = QA_PLUGIN_DIR . $pluginDirectory . '/';
}
}
return $pluginDirectories;
}
public function setEnabledPlugins($array)
{
$this->setEnabledPluginsOption($array);
}
public function getFilesystemPlugins($fullPath = false)
{
$result = array();
$fileSystemPluginFiles = glob(QA_PLUGIN_DIR . '*/qa-plugin.php');
foreach ($fileSystemPluginFiles as $pluginFile) {
$directory = dirname($pluginFile) . '/';
if (!$fullPath) {
$directory = basename($directory);
}
$result[] = $directory;
}
return $result;
}
public function getHashesForPlugins($pluginDirectories)
{
$result = array();
foreach ($pluginDirectories as $pluginDirectory) {
$result[$pluginDirectory] = md5($pluginDirectory);
}
return $result;
}
private function getEnabledPluginsOption()
{
return explode(self::PLUGIN_DELIMITER, qa_opt(self::OPT_ENABLED_PLUGINS));
}
private function setEnabledPluginsOption($array)
{
qa_opt(self::OPT_ENABLED_PLUGINS, implode(self::PLUGIN_DELIMITER, $array));
}
public function cleanRemovedPlugins()
{
$finalEnabledPlugins = array_intersect(
$this->getFilesystemPlugins(),
$this->getEnabledPlugins()
);
$this->setEnabledPluginsOption($finalEnabledPlugins);
}
}
<?php
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/Q2A/Storage/FileCache.php
Description: Interface for drivers of caching system.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
/**
* Interface for caching drivers.
*/
interface Q2A_Storage_CacheDriver
{
/**
* Get the cached data for the supplied key. Data can be any format but is usually an array.
* @param string $key The unique cache identifier.
*
* @return mixed The cached data, or null otherwise.
*/
public function get($key);
/**
* Store something in the cache along with the key and expiry time. Data gets 'serialized' to a string before storing.
* @param string $key The unique cache identifier.
* @param mixed $data The data to cache (in core Q2A this is usually an array).
* @param int $ttl Number of minutes for which to cache the data.
*
* @return bool Whether the file was successfully cached.
*/
public function set($key, $data, $ttl);
/**
* Delete an item from the cache.
* @param string $key The unique cache identifier.
*
* @return bool Whether the operation succeeded.
*/
public function delete($key);
/**
* Delete multiple items from the cache.
* @param int $limit Maximum number of items to process. 0 = unlimited
* @param int $start Offset from which to start (used for 'batching' deletes).
* @param bool $expiredOnly Delete cache only if it has expired.
*
* @return int Number of files deleted.
*/
public function clear($limit = 0, $start = 0, $expiredOnly = false);
/**
* Whether caching is available.
*
* @return bool
*/
public function isEnabled();
/**
* Get the last error.
*
* @return string
*/
public function getError();
/**
* Get current statistics for the cache.
*
* @return array Array of stats: 'files' => number of files, 'size' => total file size in bytes.
*/
public function getStats();
}
<?php
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/Q2A/Storage/CacheManager.php
Description: Handler for caching system.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
/**
* Caches data (typically from database queries) to the filesystem.
*/
class Q2A_Storage_CacheFactory
{
private static $cacheDriver = null;
/**
* Get the appropriate cache handler.
* @return Q2A_Storage_CacheInterface The cache handler.
*/
public static function getCacheDriver()
{
if (self::$cacheDriver === null) {
$config = array(
'enabled' => (int) qa_opt('caching_enabled') === 1,
'dir' => defined('QA_CACHE_DIRECTORY') ? QA_CACHE_DIRECTORY : null,
);
$driver = qa_opt('caching_driver');
switch($driver)
{
case 'memcached':
self::$cacheDriver = new Q2A_Storage_MemcachedDriver($config);
break;
case 'filesystem':
default:
self::$cacheDriver = new Q2A_Storage_FileCacheDriver($config);
break;
}
}
return self::$cacheDriver;
}
}
<?php
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/Q2A/Storage/FileCacheDriver.php
Description: File-based driver for caching system.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
/**
* Caches data (typically from database queries) to the filesystem.
*/
class Q2A_Storage_FileCacheDriver implements Q2A_Storage_CacheDriver
{
private $enabled = false;
private $error;
private $cacheDir;
/**
* Creates a new FileCache instance and checks we can write to the cache directory.
* @param array $config Configuration data, including cache storage directory.
*/
public function __construct($config)
{
if (!$config['enabled']) {
return;
}
if (isset($config['dir'])) {
$this->cacheDir = realpath($config['dir']);
if (!is_writable($this->cacheDir)) {
$this->error = qa_lang_html_sub('admin/caching_dir_error', $config['dir']);
} elseif (strpos($this->cacheDir, realpath($_SERVER['DOCUMENT_ROOT'])) === 0 || strpos($this->cacheDir, realpath(QA_BASE_DIR)) === 0) {
// check the folder is outside the public root - checks against server root and Q2A root, in order to handle symbolic links
$this->error = qa_lang_html_sub('admin/caching_dir_public', $config['dir']);
}
} else {
$this->error = qa_lang_html('admin/caching_dir_missing');
}
$this->enabled = empty($this->error);
}
/**
* Get the cached data for the supplied key.
* @param string $key The unique cache identifier.
*
* @return string The cached data, or null otherwise.
*/
public function get($key)
{
if (!$this->enabled) {
return null;
}
$file = $this->getFilename($key);
if (is_readable($file)) {
$lines = file($file, FILE_IGNORE_NEW_LINES);
$actualKey = array_shift($lines);
// double check this is the correct data
if ($key === $actualKey) {
$expiry = array_shift($lines);
if (is_numeric($expiry) && time() < $expiry) {
$encData = implode("\n", $lines);
// decode data, ignoring any notices
$data = @unserialize($encData);
if ($data !== false) {
return $data;
}
}
}
}
return null;
}
/**
* Store something in the cache along with the key and expiry time. Data gets 'serialized' to a string before storing.
* @param string $key The unique cache identifier.
* @param mixed $data The data to cache (in core Q2A this is usually an array).
* @param int $ttl Number of minutes for which to cache the data.
*
* @return bool Whether the file was successfully cached.
*/
public function set($key, $data, $ttl)
{
$success = false;
$ttl = (int) $ttl;
if ($this->enabled && $ttl > 0) {
$encData = serialize($data);
$expiry = time() + ($ttl * 60);
$cache = $key . "\n" . $expiry . "\n" . $encData;
$file = $this->getFilename($key);
$dir = dirname($file);
if (is_dir($dir) || mkdir($dir, 0777, true)) {
$success = @file_put_contents($file, $cache) !== false;
}
}
return $success;
}
/**
* Delete an item from the cache.
* @param string $key The unique cache identifier.
*
* @return bool Whether the operation succeeded.
*/
public function delete($key)
{
if ($this->enabled) {
$file = $this->getFilename($key);
$dir = dirname($key);
return $this->deleteFile($file);
}
return false;
}
/**
* Delete multiple items from the cache.
* @param int $limit Maximum number of items to process. 0 = unlimited
* @param int $start Offset from which to start (used for 'batching' deletes).
* @param bool $expiredOnly Delete cache only if it has expired.
*
* @return int Number of files deleted.
*/
public function clear($limit = 0, $start = 0, $expiredOnly = false)
{
$seek = $processed = $deleted = 0;
// fetch directories first to lower memory usage
$cacheDirs = glob($this->cacheDir . '/*/*', GLOB_ONLYDIR);
foreach ($cacheDirs as $dir) {
$cacheFiles = glob($dir . '/*');
foreach ($cacheFiles as $file) {
if ($seek < $start) {
$seek++;
continue;
}
$wasDeleted = false;
if ($expiredOnly) {
if (is_readable($file)) {
$fp = fopen($file, 'r');
$key = fgets($fp);
$expiry = (int) trim(fgets($fp));
if (is_numeric($expiry) && time() > $expiry) {
$wasDeleted = $this->deleteFile($file);
}
}
} else {
$wasDeleted = $this->deleteFile($file);
}
if ($wasDeleted) {
$deleted++;
}
$processed++;
if ($processed >= $limit) {
break 2;
}
}
}
// return how many files were deleted - caller can figure out how many to skip next time
return $deleted;
}
/**
* Whether caching is available.
*
* @return bool
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* Get the last error.
*
* @return string
*/
public function getError()
{
return $this->error;
}
/**
* Get current statistics for the cache.
*
* @return array Array of stats: 'files' => number of files, 'size' => total file size in bytes.
*/
public function getStats()
{
if (!$this->enabled) {
return array('files' => 0, 'size' => 0);
}
$totalFiles = 0;
$totalBytes = 0;
$dirIter = new RecursiveDirectoryIterator($this->cacheDir);
foreach (new RecursiveIteratorIterator($dirIter) as $file) {
if (strpos($file->getFilename(), '.') === 0) {
// TODO: use FilesystemIterator::SKIP_DOTS once we're on minimum PHP 5.3
continue;
}
$totalFiles++;
$totalBytes += $file->getSize();
}
return array(
'files' => $totalFiles,
'size' => $totalBytes,
);
}
/**
* Delete a specific file
* @param string $file Filename to delete.
*
* @return bool Whether the file was deleted successfully.
*/
private function deleteFile($file)
{
if (is_writable($file)) {
return @unlink($file) === true;
}
return false;
}
/**
* Generates filename for cache key, of the form `1/23/123abc`
* @param string $key The unique cache key.
*
* @return string
*/
private function getFilename($key)
{
$filename = sha1($key);
return $this->cacheDir . '/' . substr($filename, 0, 1) . '/' . substr($filename, 1, 2) . '/' . $filename;
}
}
<?php
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/Q2A/Storage/MemcachedDriver.php
Description: Memcached-based driver for caching system.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
/**
* Caches data (typically from database queries) in memory using Memcached.
*/
class Q2A_Storage_MemcachedDriver implements Q2A_Storage_CacheDriver
{
private $memcached;
private $enabled = false;
private $error;
private $flushed = false;
const HOST = '127.0.0.1';
const PORT = 11211;
/**
* Creates a new Memcached instance and checks we can cache items.
* @param array $config Configuration data, including cache storage directory.
*
* @return void
*/
public function __construct($config)
{
if (!$config['enabled']) {
return;
}
if (extension_loaded('memcached')) {
$this->memcached = new Memcached;
$this->memcached->addServer(self::HOST, self::PORT);
if ($this->memcached->set('q2a.test', 'TEST')) {
$this->enabled = true;
} else {
$this->setMemcachedError();
}
} else {
$this->error = 'The Memcached PHP extension is not installed';
}
}
/**
* Get the cached data for the supplied key. Data can be any format but is usually an array.
* @param string $key The unique cache identifier.
*
* @return mixed The cached data, or null otherwise.
*/
public function get($key)
{
if (!$this->enabled) {
return null;
}
$result = $this->memcached->get($key);
if ($result === false) {
$this->setMemcachedError();
return null;
}
return $result;
}
/**
* Store something in the cache along with the key and expiry time. Data gets 'serialized' to a string before storing.
* @param string $key The unique cache identifier.
* @param mixed $data The data to cache (in core Q2A this is usually an array).
* @param int $ttl Number of minutes for which to cache the data.
*
* @return bool Whether the file was successfully cached.
*/
public function set($key, $data, $ttl)
{
if (!$this->enabled) {
return false;
}
$ttl = (int) $ttl;
$expiry = time() + ($ttl * 60);
$success = $this->memcached->set($key, $data, $expiry);
if (!$success) {
$this->setMemcachedError();
}
return $success;
}
/**
* Delete an item from the cache.
* @param string $key The unique cache identifier.
*
* @return bool Whether the operation succeeded.
*/
public function delete($key)
{
if (!$this->enabled) {
return false;
}
$success = $this->memcached->delete($key);
if (!$success) {
$this->setMemcachedError();
}
return $success;
}
/**
* Delete multiple items from the cache.
* @param int $limit Maximum number of items to process. 0 = unlimited
* @param int $start Offset from which to start (used for 'batching' deletes).
* @param bool $expiredOnly This parameter is ignored because Memcached automatically clears expired items.
*
* @return int Number of files deleted. For Memcached we return 0
*/
public function clear($limit = 0, $start = 0, $expiredOnly = false)
{
if ($this->enabled && !$expiredOnly && !$this->flushed) {
$success = $this->memcached->flush();
// avoid multiple calls to flush()
$this->flushed = true;
if (!$success) {
$this->setMemcachedError();
}
}
return 0;
}
/**
* Whether caching is available.
*
* @return bool
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* Get the last error.
*
* @return string
*/
public function getError()
{
return $this->error;
}
/**
* Get current statistics for the cache.
*
* @return array Array of stats: 'files' => number of files, 'size' => total file size in bytes.
*/
public function getStats()
{
$totalFiles = 0;
$totalBytes = 0;
if ($this->enabled) {
$stats = $this->memcached->getStats();
$key = self::HOST . ':' . self::PORT;
$totalFiles = isset($stats[$key]['curr_items']) ? $stats[$key]['curr_items'] : 0;
$totalBytes = isset($stats[$key]['bytes']) ? $stats[$key]['bytes'] : 0;
}
return array(
'files' => $totalFiles,
'size' => $totalBytes,
);
}
/**
* Set current error to Memcached result message
*
* @return void
*/
private function setMemcachedError()
{
$this->error = 'Memcached error: ' . $this->memcached->getResultMessage();
}
}
......@@ -45,7 +45,7 @@ class Q2A_Util_Metadata
* @param string $url URL linking to a metadata.json file
* @return array The metadata fetched from the file
*/
public function fetchFromUrl($url, $type='Plugin')
public function fetchFromUrl($url, $type = 'Plugin')
{
$contents = qa_retrieve_url($url);
$metadata = $this->getArrayFromJson($contents);
......
......@@ -68,6 +68,7 @@ class Q2A_Util_Usage
/**
* Mark the beginning of a new stage of script execution and store usages accordingly.
* @param $stage
*/
public function mark($stage)
{
......@@ -78,6 +79,10 @@ class Q2A_Util_Usage
/**
* Logs query and updates database usage stats.
* @param $query
* @param $usedtime
* @param $gotrows
* @param $gotcolumns
*/
public function logDatabaseQuery($query, $usedtime, $gotrows, $gotcolumns)
{
......@@ -102,6 +107,8 @@ class Q2A_Util_Usage
public function output()
{
$totaldelta = $this->delta($this->startUsage, $this->getCurrent());
$stages = $this->stages;
$stages['total'] = $totaldelta;
?>
<style>
.debug-table { border-collapse: collapse; width: auto; margin: 20px auto; }
......@@ -148,31 +155,23 @@ class Q2A_Util_Usage
</tr>
</thead>
<tbody>
<?php
$stages = $this->stages;
$stages['total'] = $totaldelta;
foreach ($stages as $stage => $stagedelta):
?>
<tr>
<td class="row-heading"><?php echo ucfirst($stage); ?></td>
<td><?php echo sprintf('%.1f', $stagedelta['clock'] * 1000); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['clock'] * 100 / $totaldelta['clock']); ?></td>
<td><?php echo sprintf('%.1f', $stagedelta['cpu'] * 1000); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['cpu'] * 100 / $totaldelta['clock']); ?></td>
<td><?php echo $stagedelta['files']; ?></td>
<td><?php echo sprintf('%.1f', $stagedelta['mysql'] * 1000); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['mysql'] * 100 / $totaldelta['clock']); ?></td>
<td><?php echo $stagedelta['queries']; ?></td>
<td><?php echo sprintf('%.1f', $stagedelta['other'] * 1000); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['other'] * 100 / $totaldelta['clock']); ?></td>
<td><?php echo sprintf('%dk', $stagedelta['ram'] / 1024); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['ram'] ? ($stagedelta['ram'] * 100 / $totaldelta['ram']) : 0); ?></td>
</tr>
<?php
endforeach;
?>
<?php foreach ($stages as $stage => $stagedelta) : ?>
<tr>
<td class="row-heading"><?php echo ucfirst($stage); ?></td>
<td><?php echo sprintf('%.1f', $stagedelta['clock'] * 1000); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['clock'] * 100 / $totaldelta['clock']); ?></td>
<td><?php echo sprintf('%.1f', $stagedelta['cpu'] * 1000); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['cpu'] * 100 / $totaldelta['clock']); ?></td>
<td><?php echo $stagedelta['files']; ?></td>
<td><?php echo sprintf('%.1f', $stagedelta['mysql'] * 1000); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['mysql'] * 100 / $totaldelta['clock']); ?></td>
<td><?php echo $stagedelta['queries']; ?></td>
<td><?php echo sprintf('%.1f', $stagedelta['other'] * 1000); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['other'] * 100 / $totaldelta['clock']); ?></td>
<td><?php echo sprintf('%dk', $stagedelta['ram'] / 1024); ?></td>
<td><?php echo sprintf('%d%%', $stagedelta['ram'] ? ($stagedelta['ram'] * 100 / $totaldelta['ram']) : 0); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
......@@ -197,6 +196,9 @@ class Q2A_Util_Usage
/**
* Return the difference between two resource usage arrays, as an array.
* @param $oldusage
* @param $newusage
* @return array
*/
private function delta($oldusage, $newusage)
{
......@@ -207,5 +209,4 @@ class Q2A_Util_Usage
return $delta;
}
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-answer.php
Description: Server-side response to Ajax create answer requests
......@@ -20,84 +19,80 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/limits.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
// Load relevant information about this question
// Load relevant information about this question
$questionid=qa_post_text('a_questionid');
$userid=qa_get_logged_in_userid();
$questionid = qa_post_text('a_questionid');
$userid = qa_get_logged_in_userid();
list($question, $childposts)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_child_posts_selectspec($userid, $questionid)
);
list($question, $childposts) = qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_child_posts_selectspec($userid, $questionid)
);
// Check if the question exists, is not closed, and whether the user has permission to do this
// Check if the question exists, is not closed, and whether the user has permission to do this
if ((@$question['basetype']=='Q') && (!isset($question['closedbyid'])) && !qa_user_post_permit_error('permit_post_a', $question, QA_LIMIT_ANSWERS)) {
require_once QA_INCLUDE_DIR.'app/captcha.php';
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR.'app/post-create.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'pages/question-view.php';
require_once QA_INCLUDE_DIR.'pages/question-submit.php';
if (@$question['basetype'] == 'Q' && !isset($question['closedbyid']) && !qa_user_post_permit_error('permit_post_a', $question, QA_LIMIT_ANSWERS)) {
require_once QA_INCLUDE_DIR . 'app/captcha.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'app/post-create.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'pages/question-view.php';
require_once QA_INCLUDE_DIR . 'pages/question-submit.php';
// Try to create the new answer
// Try to create the new answer
$usecaptcha=qa_user_use_captcha(qa_user_level_for_post($question));
$answers=qa_page_q_load_as($question, $childposts);
$answerid=qa_page_q_add_a_submit($question, $answers, $usecaptcha, $in, $errors);
$usecaptcha = qa_user_use_captcha(qa_user_level_for_post($question));
$answers = qa_page_q_load_as($question, $childposts);
$answerid = qa_page_q_add_a_submit($question, $answers, $usecaptcha, $in, $errors);
// If successful, page content will be updated via Ajax
// If successful, page content will be updated via Ajax
if (isset($answerid)) {
$answer=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $answerid));
if (isset($answerid)) {
$answer = qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $answerid));
$question=$question+qa_page_q_post_rules($question, null, null, $childposts); // array union
$answer=$answer+qa_page_q_post_rules($answer, $question, $answers, null);
$question = $question + qa_page_q_post_rules($question, null, null, $childposts); // array union
$answer = $answer + qa_page_q_post_rules($answer, $question, $answers, null);
$usershtml=qa_userids_handles_html(array($answer), true);
$usershtml = qa_userids_handles_html(array($answer), true);
$a_view=qa_page_q_answer_view($question, $answer, false, $usershtml, false);
$a_view = qa_page_q_answer_view($question, $answer, false, $usershtml, false);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null);
$themeclass->initialize();
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
echo "QA_AJAX_RESPONSE\n1\n";
// Send back whether the 'answer' button should still be visible
// Send back whether the 'answer' button should still be visible
echo (int)qa_opt('allow_multi_answers')."\n";
echo (int)qa_opt('allow_multi_answers') . "\n";
// Send back the count of answers
// Send back the count of answers
$countanswers=$question['acount']+1;
$countanswers = $question['acount'] + 1;
if ($countanswers==1)
echo qa_lang_html('question/1_answer_title')."\n";
else
echo qa_lang_html_sub('question/x_answers_title', $countanswers)."\n";
if ($countanswers == 1) {
echo qa_lang_html('question/1_answer_title') . "\n";
} else {
echo qa_lang_html_sub('question/x_answers_title', $countanswers) . "\n";
}
// Send back the HTML
// Send back the HTML
$themeclass->a_list_item($a_view);
$themeclass->a_list_item($a_view);
return;
}
return;
}
}
echo "QA_AJAX_RESPONSE\n0\n"; // fall back to non-Ajax submission if there were any problems
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n0\n"; // fall back to non-Ajax submission if there were any problems
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-asktitle.php
Description: Server-side response to Ajax request based on ask a question title
......@@ -20,86 +19,82 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'util/string.php';
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
// Collect the information we need from the database
// Collect the information we need from the database
$intitle = qa_post_text('title');
$doaskcheck = qa_opt('do_ask_check_qs');
$doexampletags = qa_using_tags() && qa_opt('do_example_tags');
$intitle = qa_post_text('title');
$doaskcheck = qa_opt('do_ask_check_qs');
$doexampletags = qa_using_tags() && qa_opt('do_example_tags');
if ($doaskcheck || $doexampletags) {
$countqs = max($doexampletags ? QA_DB_RETRIEVE_ASK_TAG_QS : 0, $doaskcheck ? qa_opt('page_size_ask_check_qs') : 0);
if ($doaskcheck || $doexampletags) {
$countqs = max($doexampletags ? QA_DB_RETRIEVE_ASK_TAG_QS : 0, $doaskcheck ? qa_opt('page_size_ask_check_qs') : 0);
$relatedquestions = qa_db_select_with_pending(
qa_db_search_posts_selectspec(null, qa_string_to_words($intitle), null, null, null, null, 0, false, $countqs)
);
}
$relatedquestions = qa_db_select_with_pending(
qa_db_search_posts_selectspec(null, qa_string_to_words($intitle), null, null, null, null, 0, false, $countqs)
);
}
// Collect example tags if appropriate
// Collect example tags if appropriate
if ($doexampletags) {
$tagweight = array();
foreach ($relatedquestions as $question) {
$tags = qa_tagstring_to_tags($question['tags']);
foreach ($tags as $tag)
@$tagweight[$tag] += exp($question['score']);
if ($doexampletags) {
$tagweight = array();
foreach ($relatedquestions as $question) {
$tags = qa_tagstring_to_tags($question['tags']);
foreach ($tags as $tag) {
@$tagweight[$tag] += exp($question['score']);
}
}
arsort($tagweight, SORT_NUMERIC);
arsort($tagweight, SORT_NUMERIC);
$exampletags = array();
$exampletags = array();
$minweight = exp(qa_match_to_min_score(qa_opt('match_example_tags')));
$maxcount = qa_opt('page_size_ask_tags');
$minweight = exp(qa_match_to_min_score(qa_opt('match_example_tags')));
$maxcount = qa_opt('page_size_ask_tags');
foreach ($tagweight as $tag => $weight) {
if ($weight < $minweight)
break;
foreach ($tagweight as $tag => $weight) {
if ($weight < $minweight)
break;
$exampletags[] = $tag;
if (count($exampletags) >= $maxcount)
break;
}
$exampletags[] = $tag;
if (count($exampletags) >= $maxcount)
break;
}
else
$exampletags = array();
} else {
$exampletags = array();
}
// Output the response header and example tags
// Output the response header and example tags
echo "QA_AJAX_RESPONSE\n1\n";
echo "QA_AJAX_RESPONSE\n1\n";
echo strtr(qa_html(implode(',', $exampletags)), "\r\n", ' ') . "\n";
echo strtr(qa_html(implode(',', $exampletags)), "\r\n", ' ') . "\n";
// Collect and output the list of related questions
// Collect and output the list of related questions
if ($doaskcheck) {
$minscore = qa_match_to_min_score(qa_opt('match_ask_check_qs'));
$maxcount = qa_opt('page_size_ask_check_qs');
if ($doaskcheck) {
$minscore = qa_match_to_min_score(qa_opt('match_ask_check_qs'));
$maxcount = qa_opt('page_size_ask_check_qs');
$relatedquestions = array_slice($relatedquestions, 0, $maxcount);
$limitedquestions = array();
$relatedquestions = array_slice($relatedquestions, 0, $maxcount);
$limitedquestions = array();
foreach ($relatedquestions as $question) {
if ($question['score'] < $minscore)
break;
foreach ($relatedquestions as $question) {
if ($question['score'] < $minscore)
break;
$limitedquestions[] = $question;
}
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'ajax-asktitle', null, null);
$themeclass->initialize();
$themeclass->q_ask_similar($limitedquestions, qa_lang_html('question/ask_same_q'));
$limitedquestions[] = $question;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'ajax-asktitle', null, null);
$themeclass->initialize();
$themeclass->q_ask_similar($limitedquestions, qa_lang_html('question/ask_same_q'));
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-category.php
Description: Server-side response to Ajax category information requests
......@@ -20,26 +19,23 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
$categoryid=qa_post_text('categoryid');
if (!strlen($categoryid))
$categoryid=null;
$categoryid = qa_post_text('categoryid');
if (!strlen($categoryid))
$categoryid = null;
list($fullcategory, $categories)=qa_db_select_with_pending(
qa_db_full_category_selectspec($categoryid, true),
qa_db_category_sub_selectspec($categoryid)
);
list($fullcategory, $categories) = qa_db_select_with_pending(
qa_db_full_category_selectspec($categoryid, true),
qa_db_category_sub_selectspec($categoryid)
);
echo "QA_AJAX_RESPONSE\n1\n";
echo "QA_AJAX_RESPONSE\n1\n";
echo qa_html(strtr(@$fullcategory['content'], "\r\n", ' ')); // category description
echo qa_html(strtr(@$fullcategory['content'], "\r\n", ' ')); // category description
foreach ($categories as $category)
echo "\n".$category['categoryid'].'/'.$category['title']; // subcategory information
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
foreach ($categories as $category) {
// subcategory information
echo "\n" . $category['categoryid'] . '/' . $category['title'];
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-click-admin.php
Description: Server-side response to Ajax single clicks on posts in admin section
......@@ -20,22 +19,17 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/admin.php';
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/admin.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
$entityid=qa_post_text('entityid');
$action=qa_post_text('action');
$entityid = qa_post_text('entityid');
$action = qa_post_text('action');
if (!qa_check_form_security_code('admin/click', qa_post_text('code')))
echo "QA_AJAX_RESPONSE\n0\n".qa_lang('misc/form_security_reload');
elseif (qa_admin_single_click($entityid, $action)) // permission check happens in here
echo "QA_AJAX_RESPONSE\n1\n";
else
echo "QA_AJAX_RESPONSE\n0\n".qa_lang('main/general_error');
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
if (!qa_check_form_security_code('admin/click', qa_post_text('code')))
echo "QA_AJAX_RESPONSE\n0\n" . qa_lang('misc/form_security_reload');
elseif (qa_admin_single_click($entityid, $action)) // permission check happens in here
echo "QA_AJAX_RESPONSE\n1\n";
else
echo "QA_AJAX_RESPONSE\n0\n" . qa_lang('main/general_error');
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-click-answer.php
Description: Server-side response to Ajax single clicks on answer
......@@ -20,99 +19,94 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'pages/question-view.php';
require_once QA_INCLUDE_DIR.'pages/question-submit.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'pages/question-view.php';
require_once QA_INCLUDE_DIR . 'pages/question-submit.php';
require_once QA_INCLUDE_DIR . 'util/sort.php';
// Load relevant information about this answer
// Load relevant information about this answer
$answerid=qa_post_text('answerid');
$questionid=qa_post_text('questionid');
$answerid = qa_post_text('answerid');
$questionid = qa_post_text('questionid');
$userid=qa_get_logged_in_userid();
$userid = qa_get_logged_in_userid();
list($answer, $question, $qchildposts, $achildposts)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $answerid),
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_child_posts_selectspec($userid, $questionid),
qa_db_full_child_posts_selectspec($userid, $answerid)
);
list($answer, $question, $qchildposts, $achildposts) = qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $answerid),
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_child_posts_selectspec($userid, $questionid),
qa_db_full_child_posts_selectspec($userid, $answerid)
);
// Check if there was an operation that succeeded
// Check if there was an operation that succeeded
if (
(@$answer['basetype']=='A') &&
(@$question['basetype']=='Q')
) {
$answers=qa_page_q_load_as($question, $qchildposts);
if (@$answer['basetype'] == 'A' && @$question['basetype'] == 'Q') {
$answers = qa_page_q_load_as($question, $qchildposts);
$question=$question+qa_page_q_post_rules($question, null, null, $qchildposts); // array union
$answer=$answer+qa_page_q_post_rules($answer, $question, $qchildposts, $achildposts);
$question = $question + qa_page_q_post_rules($question, null, null, $qchildposts); // array union
$answer = $answer + qa_page_q_post_rules($answer, $question, $qchildposts, $achildposts);
if (qa_page_q_single_click_a($answer, $question, $answers, $achildposts, false, $error)) {
list($answer, $question)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $answerid),
qa_db_full_post_selectspec($userid, $questionid)
);
if (qa_page_q_single_click_a($answer, $question, $answers, $achildposts, false, $error)) {
list($answer, $question) = qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $answerid),
qa_db_full_post_selectspec($userid, $questionid)
);
// If so, page content to be updated via Ajax
// If so, page content to be updated via Ajax
echo "QA_AJAX_RESPONSE\n1\n";
echo "QA_AJAX_RESPONSE\n1\n";
// Send back new count of answers
// Send back new count of answers
$countanswers=$question['acount'];
$countanswers = $question['acount'];
if ($countanswers==1)
echo qa_lang_html('question/1_answer_title');
else
echo qa_lang_html_sub('question/x_answers_title', $countanswers);
if ($countanswers == 1)
echo qa_lang_html('question/1_answer_title');
else
echo qa_lang_html_sub('question/x_answers_title', $countanswers);
// If the answer was not deleted....
// If the answer was not deleted....
if (isset($answer)) {
$question=$question+qa_page_q_post_rules($question, null, null, $qchildposts); // array union
$answer=$answer+qa_page_q_post_rules($answer, $question, $qchildposts, $achildposts);
if (isset($answer)) {
$question = $question + qa_page_q_post_rules($question, null, null, $qchildposts); // array union
$answer = $answer + qa_page_q_post_rules($answer, $question, $qchildposts, $achildposts);
$commentsfollows=qa_page_q_load_c_follows($question, $qchildposts, $achildposts);
$commentsfollows = qa_page_q_load_c_follows($question, $qchildposts, $achildposts);
foreach ($commentsfollows as $key => $commentfollow)
$commentsfollows[$key]=$commentfollow+qa_page_q_post_rules($commentfollow, $answer, $commentsfollows, null);
$usershtml=qa_userids_handles_html(array_merge(array($answer), $commentsfollows), true);
foreach ($commentsfollows as $key => $commentfollow) {
$commentsfollows[$key] = $commentfollow + qa_page_q_post_rules($commentfollow, $answer, $commentsfollows, null);
}
$a_view=qa_page_q_answer_view($question, $answer, ($answer['postid']==$question['selchildid']) && ($answer['type']=='A'),
$usershtml, false);
$usershtml = qa_userids_handles_html(array_merge(array($answer), $commentsfollows), true);
qa_sort_by($commentsfollows, 'created');
$a_view['c_list']=qa_page_q_comment_follow_list($question, $answer, $commentsfollows, false, $usershtml, false, null);
$a_view = qa_page_q_answer_view($question, $answer, ($answer['postid'] == $question['selchildid'] && $answer['type'] == 'A'),
$usershtml, false);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null);
$themeclass->initialize();
$a_view['c_list'] = qa_page_q_comment_follow_list($question, $answer, $commentsfollows, false, $usershtml, false, null);
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null);
$themeclass->initialize();
// ... send back the HTML for it
echo "\n";
// ... send back the HTML for it
$themeclass->a_list_item($a_view);
}
echo "\n";
return;
$themeclass->a_list_item($a_view);
}
}
echo "QA_AJAX_RESPONSE\n0\n"; // fall back to non-Ajax submission if something failed
return;
}
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n0\n"; // fall back to non-Ajax submission if something failed
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-click-comment.php
Description: Server-side response to Ajax single clicks on comments
......@@ -20,78 +19,69 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'pages/question-view.php';
require_once QA_INCLUDE_DIR.'pages/question-submit.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'pages/question-view.php';
require_once QA_INCLUDE_DIR . 'pages/question-submit.php';
// Load relevant information about this comment
// Load relevant information about this comment
$commentid=qa_post_text('commentid');
$questionid=qa_post_text('questionid');
$parentid=qa_post_text('parentid');
$commentid = qa_post_text('commentid');
$questionid = qa_post_text('questionid');
$parentid = qa_post_text('parentid');
$userid=qa_get_logged_in_userid();
$userid = qa_get_logged_in_userid();
list($comment, $question, $parent, $children)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $commentid),
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid),
qa_db_full_child_posts_selectspec($userid, $parentid)
);
list($comment, $question, $parent, $children) = qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $commentid),
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid),
qa_db_full_child_posts_selectspec($userid, $parentid)
);
// Check if there was an operation that succeeded
// Check if there was an operation that succeeded
if (
(@$comment['basetype']=='C') &&
(@$question['basetype']=='Q') &&
((@$parent['basetype']=='Q') || (@$parent['basetype']=='A'))
) {
$comment=$comment+qa_page_q_post_rules($comment, $parent, $children, null); // array union
if (@$comment['basetype'] == 'C' && @$question['basetype'] == 'Q' &&
(@$parent['basetype'] == 'Q' || @$parent['basetype'] == 'A')
) {
$comment = $comment + qa_page_q_post_rules($comment, $parent, $children, null); // array union
if (qa_page_q_single_click_c($comment, $question, $parent, $error)) {
$comment=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $commentid));
if (qa_page_q_single_click_c($comment, $question, $parent, $error)) {
$comment = qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $commentid));
// If so, page content to be updated via Ajax
// If so, page content to be updated via Ajax
echo "QA_AJAX_RESPONSE\n1";
echo "QA_AJAX_RESPONSE\n1";
// If the comment was not deleted...
if (isset($comment)) {
$parent = $parent + qa_page_q_post_rules($parent, ($questionid == $parentid) ? null : $question, null, $children);
// in theory we should retrieve the parent's siblings for the above, but they're not going to be relevant
$comment = $comment + qa_page_q_post_rules($comment, $parent, $children, null);
// If the comment was not deleted...
$usershtml = qa_userids_handles_html(array($comment), true);
if (isset($comment)) {
$parent=$parent+qa_page_q_post_rules($parent, ($questionid==$parentid) ? null : $question, null, $children);
// in theory we should retrieve the parent's siblings for the above, but they're not going to be relevant
$comment=$comment+qa_page_q_post_rules($comment, $parent, $children, null);
$c_view = qa_page_q_comment_view($question, $parent, $comment, $usershtml, false);
$usershtml=qa_userids_handles_html(array($comment), true);
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'ajax-comment', null, null);
$themeclass->initialize();
$c_view=qa_page_q_comment_view($question, $parent, $comment, $usershtml, false);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comment', null, null);
$themeclass->initialize();
// ... send back the HTML for it
echo "\n";
// ... send back the HTML for it
echo "\n";
$themeclass->c_list_item($c_view);
}
return;
$themeclass->c_list_item($c_view);
}
}
echo "QA_AJAX_RESPONSE\n0\n"; // fall back to non-Ajax submission if something failed
return;
}
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n0\n"; // fall back to non-Ajax submission if something failed
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-click-pm.php
Description: Server-side response to Ajax single clicks on private messages
......@@ -20,38 +19,38 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/messages.php';
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/messages.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
$loginUserId = qa_get_logged_in_userid();
$loginUserHandle = qa_get_logged_in_handle();
$loginUserId = qa_get_logged_in_userid();
$loginUserHandle = qa_get_logged_in_handle();
$fromhandle = qa_post_text('handle');
$start = (int) qa_post_text('start');
$box = qa_post_text('box');
$pagesize = qa_opt('page_size_pms');
$fromhandle = qa_post_text('handle');
$start = (int)qa_post_text('start');
$box = qa_post_text('box');
$pagesize = qa_opt('page_size_pms');
if ( !isset($loginUserId) || $loginUserHandle !== $fromhandle || !in_array($box, array('inbox', 'outbox')) ) {
echo "QA_AJAX_RESPONSE\n0\n";
return;
}
if (!isset($loginUserId) || $loginUserHandle !== $fromhandle || !in_array($box, array('inbox', 'outbox'))) {
echo "QA_AJAX_RESPONSE\n0\n";
return;
}
$func = 'qa_db_messages_'.$box.'_selectspec';
$pmSpec = $func('private', $loginUserId, true, $start, $pagesize);
$userMessages = qa_db_select_with_pending($pmSpec);
$func = 'qa_db_messages_' . $box . '_selectspec';
$pmSpec = $func('private', $loginUserId, true, $start, $pagesize);
$userMessages = qa_db_select_with_pending($pmSpec);
foreach ($userMessages as $message) {
if (qa_clicked('m'.$message['messageid'].'_dodelete')) {
if (qa_check_form_security_code('pm-'.$fromhandle, qa_post_text('code'))) {
qa_pm_delete($loginUserId, qa_get_logged_in_handle(), qa_cookie_get(), $message, $box);
echo "QA_AJAX_RESPONSE\n1\n";
return;
}
foreach ($userMessages as $message) {
if (qa_clicked('m' . $message['messageid'] . '_dodelete')) {
if (qa_check_form_security_code('pm-' . $fromhandle, qa_post_text('code'))) {
qa_pm_delete($loginUserId, qa_get_logged_in_handle(), qa_cookie_get(), $message, $box);
echo "QA_AJAX_RESPONSE\n1\n";
return;
}
}
}
echo "QA_AJAX_RESPONSE\n0\n";
echo "QA_AJAX_RESPONSE\n0\n";
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-click-wall.php
Description: Server-side response to Ajax single clicks on wall posts
......@@ -20,28 +19,26 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/messages.php';
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/messages.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
$tohandle=qa_post_text('handle');
$start=(int)qa_post_text('start');
$tohandle = qa_post_text('handle');
$start = (int)qa_post_text('start');
$usermessages=qa_db_select_with_pending(qa_db_recent_messages_selectspec(null, null, $tohandle, false, null, $start));
$usermessages=qa_wall_posts_add_rules($usermessages, $start);
$usermessages = qa_db_select_with_pending(qa_db_recent_messages_selectspec(null, null, $tohandle, false, null, $start));
$usermessages = qa_wall_posts_add_rules($usermessages, $start);
foreach ($usermessages as $message)
if (qa_clicked('m'.$message['messageid'].'_dodelete') && $message['deleteable'])
if (qa_check_form_security_code('wall-'.$tohandle, qa_post_text('code'))) {
qa_wall_delete_post(qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), $message);
echo "QA_AJAX_RESPONSE\n1\n";
return;
}
foreach ($usermessages as $message) {
if (qa_clicked('m' . $message['messageid'] . '_dodelete') && $message['deleteable']) {
if (qa_check_form_security_code('wall-' . $tohandle, qa_post_text('code'))) {
qa_wall_delete_post(qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), $message);
echo "QA_AJAX_RESPONSE\n1\n";
return;
}
}
}
echo "QA_AJAX_RESPONSE\n0\n";
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n0\n";
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-comment.php
Description: Server-side response to Ajax create comment requests
......@@ -20,85 +19,77 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/limits.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
// Load relevant information about this question and the comment parent
// Load relevant information about this question and the comment parent
$questionid=qa_post_text('c_questionid');
$parentid=qa_post_text('c_parentid');
$userid=qa_get_logged_in_userid();
$questionid = qa_post_text('c_questionid');
$parentid = qa_post_text('c_parentid');
$userid = qa_get_logged_in_userid();
list($question, $parent, $children)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid),
qa_db_full_child_posts_selectspec($userid, $parentid)
);
list($question, $parent, $children) = qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid),
qa_db_full_child_posts_selectspec($userid, $parentid)
);
// Check if the question and parent exist, and whether the user has permission to do this
// Check if the question and parent exist, and whether the user has permission to do this
if (
(@$question['basetype']=='Q') &&
((@$parent['basetype']=='Q') || (@$parent['basetype']=='A')) &&
!qa_user_post_permit_error('permit_post_c', $parent, QA_LIMIT_COMMENTS))
{
require_once QA_INCLUDE_DIR.'app/captcha.php';
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR.'app/post-create.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'pages/question-view.php';
require_once QA_INCLUDE_DIR.'pages/question-submit.php';
require_once QA_INCLUDE_DIR.'util/sort.php';
if (@$question['basetype'] == 'Q' && (@$parent['basetype'] == 'Q' || @$parent['basetype'] == 'A') &&
!qa_user_post_permit_error('permit_post_c', $parent, QA_LIMIT_COMMENTS)
) {
require_once QA_INCLUDE_DIR . 'app/captcha.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'app/post-create.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'pages/question-view.php';
require_once QA_INCLUDE_DIR . 'pages/question-submit.php';
require_once QA_INCLUDE_DIR . 'util/sort.php';
// Try to create the new comment
// Try to create the new comment
$usecaptcha=qa_user_use_captcha(qa_user_level_for_post($question));
$commentid=qa_page_q_add_c_submit($question, $parent, $children, $usecaptcha, $in, $errors);
$usecaptcha = qa_user_use_captcha(qa_user_level_for_post($question));
$commentid = qa_page_q_add_c_submit($question, $parent, $children, $usecaptcha, $in, $errors);
// If successful, page content will be updated via Ajax
// If successful, page content will be updated via Ajax
if (isset($commentid)) {
$children=qa_db_select_with_pending(qa_db_full_child_posts_selectspec($userid, $parentid));
if (isset($commentid)) {
$children = qa_db_select_with_pending(qa_db_full_child_posts_selectspec($userid, $parentid));
$parent=$parent+qa_page_q_post_rules($parent, ($questionid==$parentid) ? null : $question, null, $children);
// in theory we should retrieve the parent's siblings for the above, but they're not going to be relevant
$parent = $parent + qa_page_q_post_rules($parent, ($questionid == $parentid) ? null : $question, null, $children);
// in theory we should retrieve the parent's siblings for the above, but they're not going to be relevant
foreach ($children as $key => $child)
$children[$key]=$child+qa_page_q_post_rules($child, $parent, $children, null);
$usershtml=qa_userids_handles_html($children, true);
qa_sort_by($children, 'created');
foreach ($children as $key => $child) {
$children[$key] = $child + qa_page_q_post_rules($child, $parent, $children, null);
}
$c_list=qa_page_q_comment_follow_list($question, $parent, $children, true, $usershtml, false, null);
$usershtml = qa_userids_handles_html($children, true);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null);
$themeclass->initialize();
qa_sort_by($children, 'created');
echo "QA_AJAX_RESPONSE\n1\n";
$c_list = qa_page_q_comment_follow_list($question, $parent, $children, true, $usershtml, false, null);
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null);
$themeclass->initialize();
// Send back the ID of the new comment
echo "QA_AJAX_RESPONSE\n1\n";
echo qa_anchor('C', $commentid)."\n";
// send back the ID of the new comment
echo qa_anchor('C', $commentid) . "\n";
// Send back the HTML
$themeclass->c_list_items($c_list['cs']);
// send back the HTML
$themeclass->c_list_items($c_list['cs']);
return;
}
return;
}
}
echo "QA_AJAX_RESPONSE\n0\n"; // fall back to non-Ajax submission if there were any problems
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n0\n"; // fall back to non-Ajax submission if there were any problems
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-favorite.php
Description: Server-side response to Ajax favorite requests
......@@ -20,37 +19,31 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'app/favorites.php';
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/favorites.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
$entitytype=qa_post_text('entitytype');
$entityid=qa_post_text('entityid');
$setfavorite=qa_post_text('favorite');
$entitytype = qa_post_text('entitytype');
$entityid = qa_post_text('entityid');
$setfavorite = qa_post_text('favorite');
$userid=qa_get_logged_in_userid();
$userid = qa_get_logged_in_userid();
if (!qa_check_form_security_code('favorite-'.$entitytype.'-'.$entityid, qa_post_text('code')))
echo "QA_AJAX_RESPONSE\n0\n".qa_lang('misc/form_security_reload');
if (!qa_check_form_security_code('favorite-' . $entitytype . '-' . $entityid, qa_post_text('code'))) {
echo "QA_AJAX_RESPONSE\n0\n" . qa_lang('misc/form_security_reload');
} elseif (isset($userid)) {
$cookieid = qa_cookie_get();
elseif (isset($userid)) {
$cookieid=qa_cookie_get();
qa_user_favorite_set($userid, qa_get_logged_in_handle(), $cookieid, $entitytype, $entityid, $setfavorite);
qa_user_favorite_set($userid, qa_get_logged_in_handle(), $cookieid, $entitytype, $entityid, $setfavorite);
$favoriteform = qa_favorite_form($entitytype, $entityid, $setfavorite, qa_lang($setfavorite ? 'main/remove_favorites' : 'main/add_favorites'));
$favoriteform=qa_favorite_form($entitytype, $entityid, $setfavorite, qa_lang($setfavorite ? 'main/remove_favorites' : 'main/add_favorites'));
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'ajax-favorite', null, null);
$themeclass->initialize();
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-favorite', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
echo "QA_AJAX_RESPONSE\n1\n";
$themeclass->favorite_inner_html($favoriteform);
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
$themeclass->favorite_inner_html($favoriteform);
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-mailing.php
Description: Server-side response to Ajax mailing loop requests
......@@ -20,34 +19,29 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/mailing.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/mailing.php';
$continue=false;
$continue = false;
if (qa_get_logged_in_level()>=QA_USER_LEVEL_ADMIN) {
$starttime=time();
if (qa_get_logged_in_level() >= QA_USER_LEVEL_ADMIN) {
$starttime = time();
qa_mailing_perform_step();
qa_mailing_perform_step();
if ($starttime==time())
sleep(1); // make sure at least one second has passed
if ($starttime == time())
sleep(1); // make sure at least one second has passed
$message=qa_mailing_progress_message();
$message = qa_mailing_progress_message();
if (isset($message))
$continue=true;
else
$message=qa_lang('admin/mailing_complete');
if (isset($message))
$continue = true;
else
$message = qa_lang('admin/mailing_complete');
} else
$message=qa_lang('admin/no_privileges');
} else
$message = qa_lang('admin/no_privileges');
echo "QA_AJAX_RESPONSE\n".(int)$continue."\n".qa_html($message);
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n" . (int)$continue . "\n" . qa_html($message);
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-notice.php
Description: Server-side response to Ajax requests to close a notice
......@@ -20,34 +19,29 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'db/notices.php';
require_once QA_INCLUDE_DIR.'db/users.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'db/notices.php';
require_once QA_INCLUDE_DIR . 'db/users.php';
$noticeid=qa_post_text('noticeid');
$noticeid = qa_post_text('noticeid');
if (!qa_check_form_security_code('notice-'.$noticeid, qa_post_text('code')))
echo "QA_AJAX_RESPONSE\n0\n".qa_lang('misc/form_security_reload');
if (!qa_check_form_security_code('notice-' . $noticeid, qa_post_text('code')))
echo "QA_AJAX_RESPONSE\n0\n" . qa_lang('misc/form_security_reload');
else {
if ($noticeid=='visitor')
setcookie('qa_noticed', 1, time()+86400*3650, '/', QA_COOKIE_DOMAIN);
else {
$userid=qa_get_logged_in_userid();
if ($noticeid=='welcome')
qa_db_user_set_flag($userid, QA_USER_FLAGS_WELCOME_NOTICE, false);
else
qa_db_usernotice_delete($userid, $noticeid);
}
else {
if ($noticeid == 'visitor')
setcookie('qa_noticed', 1, time() + 86400 * 3650, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true);
else {
$userid = qa_get_logged_in_userid();
echo "QA_AJAX_RESPONSE\n1";
if ($noticeid == 'welcome')
qa_db_user_set_flag($userid, QA_USER_FLAGS_WELCOME_NOTICE, false);
else
qa_db_usernotice_delete($userid, $noticeid);
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n1";
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-recalc.php
Description: Server-side response to Ajax admin recalculation requests
......@@ -20,35 +19,30 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/recalc.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/recalc.php';
if (qa_get_logged_in_level()>=QA_USER_LEVEL_ADMIN) {
if (qa_get_logged_in_level() >= QA_USER_LEVEL_ADMIN) {
if (!qa_check_form_security_code('admin/recalc', qa_post_text('code'))) {
$state = '';
$message = qa_lang('misc/form_security_reload');
if (!qa_check_form_security_code('admin/recalc', qa_post_text('code'))) {
$state='';
$message=qa_lang('misc/form_security_reload');
} else {
$state=qa_post_text('state');
$stoptime=time()+3;
while ( qa_recalc_perform_step($state) && (time()<$stoptime) )
;
} else {
$state = qa_post_text('state');
$stoptime = time() + 3;
$message=qa_recalc_get_message($state);
while (qa_recalc_perform_step($state) && time() < $stoptime) {
// wait
}
} else {
$state='';
$message=qa_lang('admin/no_privileges');
$message = qa_recalc_get_message($state);
}
echo "QA_AJAX_RESPONSE\n1\n".$state."\n".qa_html($message);
} else {
$state = '';
$message = qa_lang('admin/no_privileges');
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n1\n" . $state . "\n" . qa_html($message);
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-show-comments.php
Description: Server-side response to Ajax request to view full comment list
......@@ -20,56 +19,57 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR.'pages/question-view.php';
require_once QA_INCLUDE_DIR.'util/sort.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'pages/question-view.php';
require_once QA_INCLUDE_DIR . 'util/sort.php';
// Load relevant information about this question and check it exists
// Load relevant information about this question and check it exists
$questionid=qa_post_text('c_questionid');
$parentid=qa_post_text('c_parentid');
$userid=qa_get_logged_in_userid();
$questionid = qa_post_text('c_questionid');
$parentid = qa_post_text('c_parentid');
$userid = qa_get_logged_in_userid();
list($question, $parent, $children)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid),
qa_db_full_child_posts_selectspec($userid, $parentid)
);
list($question, $parent, $children, $duplicateposts) = qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid),
qa_db_full_child_posts_selectspec($userid, $parentid),
qa_db_post_duplicates_selectspec($questionid)
);
if (isset($parent)) {
$parent=$parent+qa_page_q_post_rules($parent, null, null, $children);
// in theory we should retrieve the parent's parent and siblings for the above, but they're not going to be relevant
if (isset($parent)) {
$parent = $parent + qa_page_q_post_rules($parent, null, null, $children + $duplicateposts);
// in theory we should retrieve the parent's parent and siblings for the above, but they're not going to be relevant
foreach ($children as $key => $child)
$children[$key]=$child+qa_page_q_post_rules($child, $parent, $children, null);
$usershtml=qa_userids_handles_html($children, true);
foreach ($children as $key => $child) {
$children[$key] = $child + qa_page_q_post_rules($child, $parent, $children, null);
}
qa_sort_by($children, 'created');
$commentsfollows = $questionid == $parentid
? qa_page_q_load_c_follows($question, $children, array(), $duplicateposts)
: qa_page_q_load_c_follows($question, array(), $children);
$c_list=qa_page_q_comment_follow_list($question, $parent, $children, true, $usershtml, false, null);
$usershtml = qa_userids_handles_html($commentsfollows, true);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null);
$themeclass->initialize();
qa_sort_by($commentsfollows, 'created');
echo "QA_AJAX_RESPONSE\n1\n";
$c_list = qa_page_q_comment_follow_list($question, $parent, $commentsfollows, true, $usershtml, false, null);
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null);
$themeclass->initialize();
// Send back the HTML
echo "QA_AJAX_RESPONSE\n1\n";
$themeclass->c_list_items($c_list['cs']);
return;
}
// Send back the HTML
$themeclass->c_list_items($c_list['cs']);
echo "QA_AJAX_RESPONSE\n0\n";
return;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n0\n";
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-version.php
Description: Server-side response to Ajax version check requests
......@@ -20,56 +19,62 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/admin.php';
require_once QA_INCLUDE_DIR.'app/users.php';
if (qa_get_logged_in_level() < QA_USER_LEVEL_ADMIN) {
echo "QA_AJAX_RESPONSE\n0\n" . qa_lang_html('admin/no_privileges');
return;
require_once QA_INCLUDE_DIR . 'app/admin.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
if (qa_get_logged_in_level() < QA_USER_LEVEL_ADMIN) {
echo "QA_AJAX_RESPONSE\n0\n" . qa_lang_html('admin/no_privileges');
return;
}
$uri = qa_post_text('uri');
$version = qa_post_text('version');
$isCore = qa_post_text('isCore') === "true";
if ($isCore) {
$contents = qa_retrieve_url($uri);
if (strlen($contents) > 0) {
if (qa_qa_version_below($contents)) {
$response =
'<a href="https://github.com/q2a/question2answer/releases" style="color:#d00;">' .
qa_lang_html_sub('admin/version_get_x', qa_html('v' . $contents)) .
'</a>';
} else {
$response = qa_html($contents); // Output the current version number
}
} else {
$response = qa_lang_html('admin/version_latest_unknown');
}
$uri = qa_post_text('uri');
$version = qa_post_text('version');
} else {
$metadataUtil = new Q2A_Util_Metadata();
$metadata = $metadataUtil->fetchFromUrl($uri);
if (strlen(@$metadata['version'])) {
if (strlen(@$metadata['version']) > 0) {
if (strcmp($metadata['version'], $version)) {
if (qa_qa_version_below(@$metadata['min_q2a'])) {
$response = strtr(qa_lang_html('admin/version_requires_q2a'), array(
'^1' => qa_html('v'.$metadata['version']),
'^1' => qa_html('v' . $metadata['version']),
'^2' => qa_html($metadata['min_q2a']),
));
}
elseif (qa_php_version_below(@$metadata['min_php'])) {
} elseif (qa_php_version_below(@$metadata['min_php'])) {
$response = strtr(qa_lang_html('admin/version_requires_php'), array(
'^1' => qa_html('v'.$metadata['version']),
'^1' => qa_html('v' . $metadata['version']),
'^2' => qa_html($metadata['min_php']),
));
}
} else {
$response = qa_lang_html_sub('admin/version_get_x', qa_html('v' . $metadata['version']));
else {
$response = qa_lang_html_sub('admin/version_get_x', qa_html('v'.$metadata['version']));
if (strlen(@$metadata['uri']))
$response = '<a href="'.qa_html($metadata['uri']).'" style="color:#d00;">'.$response.'</a>';
if (strlen(@$metadata['uri'])) {
$response = '<a href="' . qa_html($metadata['uri']) . '" style="color:#d00;">' . $response . '</a>';
}
}
}
else
} else {
$response = qa_lang_html('admin/version_latest');
}
else
}
} else {
$response = qa_lang_html('admin/version_latest_unknown');
}
}
echo "QA_AJAX_RESPONSE\n1\n".$response;
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n1\n" . $response;
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-vote.php
Description: Server-side response to Ajax voting requests
......@@ -20,48 +19,45 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'app/votes.php';
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR.'app/options.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/votes.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
$postid=qa_post_text('postid');
$vote=qa_post_text('vote');
$code=qa_post_text('code');
$postid = qa_post_text('postid');
$vote = qa_post_text('vote');
$code = qa_post_text('code');
$userid=qa_get_logged_in_userid();
$cookieid=qa_cookie_get();
$userid = qa_get_logged_in_userid();
$cookieid = qa_cookie_get();
if (!qa_check_form_security_code('vote', $code))
$voteerror=qa_lang_html('misc/form_security_reload');
if (!qa_check_form_security_code('vote', $code)) {
$voteerror = qa_lang_html('misc/form_security_reload');
} else {
$post = qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $postid));
$voteerror = qa_vote_error_html($post, $vote, $userid, qa_request());
}
else {
$post=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $postid));
$voteerror=qa_vote_error_html($post, $vote, $userid, qa_request());
}
if ($voteerror === false) {
qa_vote_set($post, $userid, qa_get_logged_in_handle(), $cookieid, $vote);
if ($voteerror===false) {
qa_vote_set($post, $userid, qa_get_logged_in_handle(), $cookieid, $vote);
$post = qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $postid));
$post=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $postid));
$fields = qa_post_html_fields($post, $userid, $cookieid, array(), null, array(
'voteview' => qa_get_vote_view($post, true), // behave as if on question page since the vote succeeded
));
$fields=qa_post_html_fields($post, $userid, $cookieid, array(), null, array(
'voteview' => qa_get_vote_view($post, true), // behave as if on question page since the vote succeeded
));
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'voting', null, null);
$themeclass->initialize();
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'voting', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
$themeclass->voting_inner_html($fields);
echo "QA_AJAX_RESPONSE\n1\n";
$themeclass->voting_inner_html($fields);
return;
} else
echo "QA_AJAX_RESPONSE\n0\n".$voteerror;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
echo "QA_AJAX_RESPONSE\n0\n" . $voteerror;
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-ajax-wallpost.php
Description: Server-side response to Ajax wall post requests
......@@ -20,47 +19,42 @@
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'app/messages.php';
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/messages.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
$message=qa_post_text('message');
$tohandle=qa_post_text('handle');
$morelink=qa_post_text('morelink');
$message = qa_post_text('message');
$tohandle = qa_post_text('handle');
$morelink = qa_post_text('morelink');
$touseraccount=qa_db_select_with_pending(qa_db_user_account_selectspec($tohandle, false));
$loginuserid=qa_get_logged_in_userid();
$touseraccount = qa_db_select_with_pending(qa_db_user_account_selectspec($tohandle, false));
$loginuserid = qa_get_logged_in_userid();
$errorhtml=qa_wall_error_html($loginuserid, $touseraccount['userid'], $touseraccount['flags']);
$errorhtml = qa_wall_error_html($loginuserid, $touseraccount['userid'], $touseraccount['flags']);
if ($errorhtml || (!strlen($message)) || !qa_check_form_security_code('wall-'.$tohandle, qa_post_text('code')) )
echo "QA_AJAX_RESPONSE\n0"; // if there's an error, process in non-Ajax way
if ($errorhtml || !strlen($message) || !qa_check_form_security_code('wall-' . $tohandle, qa_post_text('code'))) {
echo "QA_AJAX_RESPONSE\n0"; // if there's an error, process in non-Ajax way
} else {
$messageid = qa_wall_add_post($loginuserid, qa_get_logged_in_handle(), qa_cookie_get(),
$touseraccount['userid'], $touseraccount['handle'], $message, '');
$touseraccount['wallposts']++; // won't have been updated
else {
$messageid=qa_wall_add_post($loginuserid, qa_get_logged_in_handle(), qa_cookie_get(),
$touseraccount['userid'], $touseraccount['handle'], $message, '');
$touseraccount['wallposts']++; // won't have been updated
$usermessages = qa_db_select_with_pending(qa_db_recent_messages_selectspec(null, null, $touseraccount['userid'], true, qa_opt('page_size_wall')));
$usermessages = qa_wall_posts_add_rules($usermessages, 0);
$usermessages=qa_db_select_with_pending(qa_db_recent_messages_selectspec(null, null, $touseraccount['userid'], true, qa_opt('page_size_wall')));
$usermessages=qa_wall_posts_add_rules($usermessages, 0);
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'wall', null, null);
$themeclass->initialize();
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'wall', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
echo "QA_AJAX_RESPONSE\n1\n";
echo 'm' . $messageid . "\n"; // element in list to be revealed
echo 'm'.$messageid."\n"; // element in list to be revealed
foreach ($usermessages as $message)
$themeclass->message_item(qa_wall_post_view($message));
if ($morelink && ($touseraccount['wallposts']>count($usermessages)))
$themeclass->message_item(qa_wall_view_more_link($tohandle, count($usermessages)));
foreach ($usermessages as $message) {
$themeclass->message_item(qa_wall_post_view($message));
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
if ($morelink && ($touseraccount['wallposts'] > count($usermessages)))
$themeclass->message_item(qa_wall_view_more_link($tohandle, count($usermessages)));
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-app-captcha.php
Description: Wrapper functions and utilities for captcha modules
......@@ -21,7 +20,7 @@
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
header('Location: ../../');
exit;
}
......@@ -39,6 +38,8 @@ function qa_captcha_available()
/**
* Return an HTML string explaining $captchareason (from qa_user_captcha_reason()) to the user about why they are seeing a captcha
* @param $captchareason
* @return mixed|null|string
*/
function qa_captcha_reason_note($captchareason)
{
......@@ -65,8 +66,13 @@ function qa_captcha_reason_note($captchareason)
/**
* Prepare $qa_content for showing a captcha, adding the element to $fields, given previous $errors, and a $note to display.
* Returns JavaScript required to load CAPTCHA when field is shown by user (e.g. clicking comment button).
* @param $qa_content
* @param $fields
* @param $errors
* @param $note
* @return string
*/
function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null)
function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note = null)
{
if (!qa_captcha_available())
return '';
......@@ -79,8 +85,7 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null)
if ($count > 1) {
// use blank captcha in order to load via JS
$html = '';
}
else {
} else {
// first captcha is always loaded explicitly
$qa_content['script_var']['qa_captcha_in'] = 'qa_captcha_div_1';
$html = $captcha->form_html($qa_content, @$errors['captcha']);
......@@ -89,17 +94,19 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null)
$fields['captcha'] = array(
'type' => 'custom',
'label' => qa_lang_html('misc/captcha_label'),
'html' => '<div id="qa_captcha_div_'.$count.'">'.$html.'</div>',
'html' => '<div id="qa_captcha_div_' . $count . '">' . $html . '</div>',
'error' => @array_key_exists('captcha', $errors) ? qa_lang_html('misc/captcha_error') : null,
'note' => $note,
);
return "if (!document.getElementById('qa_captcha_div_".$count."').hasChildNodes()) { recaptcha_load('qa_captcha_div_".$count."'); }";
return "if (!document.getElementById('qa_captcha_div_" . $count . "').hasChildNodes()) { recaptcha_load('qa_captcha_div_" . $count . "'); }";
}
/**
* Check if captcha is submitted correctly, and if not, set $errors['captcha'] to a descriptive string.
* @param $errors
* @return bool
*/
function qa_captcha_validate_post(&$errors)
{
......
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-app-cookies.php
Description: User cookie management (application level) for tracking anonymous posts
......@@ -20,59 +19,56 @@
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
function qa_cookie_get()
/*
Return the user identification cookie sent by the browser for this page request, or null if none
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../../');
exit;
}
return isset($_COOKIE['qa_id']) ? qa_gpc_to_string($_COOKIE['qa_id']) : null;
}
/**
* Return the user identification cookie sent by the browser for this page request, or null if none
*/
function qa_cookie_get()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
function qa_cookie_get_create()
/*
Return user identification cookie sent by browser if valid, or create a new one if not.
Either way, extend for another year (this is used when an anonymous post is created)
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return isset($_COOKIE['qa_id']) ? qa_gpc_to_string($_COOKIE['qa_id']) : null;
}
require_once QA_INCLUDE_DIR.'db/cookies.php';
$cookieid=qa_cookie_get();
/**
* Return user identification cookie sent by browser if valid, or create a new one if not.
* Either way, extend for another year (this is used when an anonymous post is created)
*/
function qa_cookie_get_create()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (isset($cookieid) && qa_db_cookie_exists($cookieid))
; // cookie is valid
else
$cookieid=qa_db_cookie_create(qa_remote_ip_address());
require_once QA_INCLUDE_DIR . 'db/cookies.php';
setcookie('qa_id', $cookieid, time()+86400*365, '/', QA_COOKIE_DOMAIN);
$_COOKIE['qa_id']=$cookieid;
$cookieid = qa_cookie_get();
return $cookieid;
if (!isset($cookieid) || !qa_db_cookie_exists($cookieid)) {
// cookie is invalid
$cookieid = qa_db_cookie_create(qa_remote_ip_address());
}
setcookie('qa_id', $cookieid, time() + 86400 * 365, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true);
$_COOKIE['qa_id'] = $cookieid;
function qa_cookie_report_action($cookieid, $action)
/*
Called after a database write $action performed by a user identified by $cookieid,
relating to $questionid, $answerid and/or $commentid
*/
{
require_once QA_INCLUDE_DIR.'db/cookies.php';
return $cookieid;
}
qa_db_cookie_written($cookieid, qa_remote_ip_address());
}
/**
* Called after a database write $action performed by a user identified by $cookieid,
* relating to $questionid, $answerid and/or $commentid
* @param $cookieid
* @param $action
*/
function qa_cookie_report_action($cookieid, $action)
{
require_once QA_INCLUDE_DIR . 'db/cookies.php';
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
qa_db_cookie_written($cookieid, qa_remote_ip_address());
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-app-emails.php
Description: Wrapper functions for sending email notifications to users
......@@ -20,159 +19,164 @@
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
require_once QA_INCLUDE_DIR.'app/options.php';
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../../');
exit;
}
require_once QA_INCLUDE_DIR . 'app/options.php';
/**
* Suspend the sending of all email notifications via qa_send_notification(...) if $suspend is true, otherwise
* reinstate it. A counter is kept to allow multiple calls.
* @param bool $suspend
*/
function qa_suspend_notifications($suspend = true)
{
global $qa_notifications_suspended;
$qa_notifications_suspended += ($suspend ? 1 : -1);
}
/**
* Send email to person with $userid and/or $email and/or $handle (null/invalid values are ignored or retrieved from
* user database as appropriate). Email uses $subject and $body, after substituting each key in $subs with its
* corresponding value, plus applying some standard substitutions such as ^site_title, ^handle and ^email.
* @param $userid
* @param $email
* @param $handle
* @param $subject
* @param $body
* @param $subs
* @param bool $html
* @return bool
*/
function qa_send_notification($userid, $email, $handle, $subject, $body, $subs, $html = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_notifications_suspended;
if ($qa_notifications_suspended > 0)
return false;
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
if (isset($userid)) {
$needemail = !qa_email_validate(@$email); // take from user if invalid, e.g. @ used in practice
$needhandle = empty($handle);
if ($needemail || $needhandle) {
if (QA_FINAL_EXTERNAL_USERS) {
if ($needhandle) {
$handles = qa_get_public_from_userids(array($userid));
$handle = @$handles[$userid];
}
function qa_suspend_notifications($suspend=true)
/*
Suspend the sending of all email notifications via qa_send_notification(...) if $suspend is true, otherwise
reinstate it. A counter is kept to allow multiple calls.
*/
{
global $qa_notifications_suspended;
if ($needemail)
$email = qa_get_user_email($userid);
$qa_notifications_suspended+=($suspend ? 1 : -1);
}
} else {
$useraccount = qa_db_select_with_pending(
array(
'columns' => array('email', 'handle'),
'source' => '^users WHERE userid = #',
'arguments' => array($userid),
'single' => true,
)
);
if ($needhandle)
$handle = @$useraccount['handle'];
function qa_send_notification($userid, $email, $handle, $subject, $body, $subs, $html = false)
/*
Send email to person with $userid and/or $email and/or $handle (null/invalid values are ignored or retrieved from
user database as appropriate). Email uses $subject and $body, after substituting each key in $subs with its
corresponding value, plus applying some standard substitutions such as ^site_title, ^handle and ^email.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_notifications_suspended;
if ($qa_notifications_suspended>0)
return false;
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'util/string.php';
if (isset($userid)) {
$needemail=!qa_email_validate(@$email); // take from user if invalid, e.g. @ used in practice
$needhandle=empty($handle);
if ($needemail || $needhandle) {
if (QA_FINAL_EXTERNAL_USERS) {
if ($needhandle) {
$handles=qa_get_public_from_userids(array($userid));
$handle=@$handles[$userid];
}
if ($needemail)
$email=qa_get_user_email($userid);
} else {
$useraccount=qa_db_select_with_pending(
array(
'columns' => array('email', 'handle'),
'source' => '^users WHERE userid = #',
'arguments' => array($userid),
'single' => true,
)
);
if ($needhandle)
$handle=@$useraccount['handle'];
if ($needemail)
$email=@$useraccount['email'];
}
if ($needemail)
$email = @$useraccount['email'];
}
}
if (isset($email) && qa_email_validate($email)) {
$subs['^site_title']=qa_opt('site_title');
$subs['^handle']=$handle;
$subs['^email']=$email;
$subs['^open']="\n";
$subs['^close']="\n";
return qa_send_email(array(
'fromemail' => qa_opt('from_email'),
'fromname' => qa_opt('site_title'),
'toemail' => $email,
'toname' => $handle,
'subject' => strtr($subject, $subs),
'body' => (empty($handle) ? '' : qa_lang_sub('emails/to_handle_prefix', $handle)).strtr($body, $subs),
'html' => $html,
));
} else
return false;
}
if (isset($email) && qa_email_validate($email)) {
$subs['^site_title'] = qa_opt('site_title');
$subs['^handle'] = $handle;
$subs['^email'] = $email;
$subs['^open'] = "\n";
$subs['^close'] = "\n";
return qa_send_email(array(
'fromemail' => qa_opt('from_email'),
'fromname' => qa_opt('site_title'),
'toemail' => $email,
'toname' => $handle,
'subject' => strtr($subject, $subs),
'body' => (empty($handle) ? '' : qa_lang_sub('emails/to_handle_prefix', $handle)) . strtr($body, $subs),
'html' => $html,
));
}
function qa_send_email($params)
/*
Send the email based on the $params array - the following keys are required (some can be empty): fromemail,
fromname, toemail, toname, subject, body, html
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// @error_log(print_r($params, true));
require_once QA_INCLUDE_DIR.'vendor/PHPMailer/PHPMailerAutoload.php';
return false;
}
$mailer=new PHPMailer();
$mailer->CharSet='utf-8';
$mailer->From=$params['fromemail'];
$mailer->Sender=$params['fromemail'];
$mailer->FromName=$params['fromname'];
$mailer->addAddress($params['toemail'], $params['toname']);
if(!empty($params['replytoemail'])){
$mailer->addReplyTo($params['replytoemail'], $params['replytoname']);
}
$mailer->Subject=$params['subject'];
$mailer->Body=$params['body'];
/**
* Send the email based on the $params array - the following keys are required (some can be empty): fromemail,
* fromname, toemail, toname, subject, body, html
* @param $params
* @return bool
*/
function qa_send_email($params)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if ($params['html'])
$mailer->isHTML(true);
// @error_log(print_r($params, true));
if (qa_opt('smtp_active')) {
$mailer->isSMTP();
$mailer->Host=qa_opt('smtp_address');
$mailer->Port=qa_opt('smtp_port');
require_once QA_INCLUDE_DIR . 'vendor/PHPMailer/PHPMailerAutoload.php';
if (qa_opt('smtp_secure')){
$mailer->SMTPSecure=qa_opt('smtp_secure');
}
else {
$mailer->SMTPOptions=array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
}
$mailer = new PHPMailer();
$mailer->CharSet = 'utf-8';
if (qa_opt('smtp_authenticate')) {
$mailer->SMTPAuth=true;
$mailer->Username=qa_opt('smtp_username');
$mailer->Password=qa_opt('smtp_password');
}
$mailer->From = $params['fromemail'];
$mailer->Sender = $params['fromemail'];
$mailer->FromName = $params['fromname'];
$mailer->addAddress($params['toemail'], $params['toname']);
if (!empty($params['replytoemail'])) {
$mailer->addReplyTo($params['replytoemail'], $params['replytoname']);
}
$mailer->Subject = $params['subject'];
$mailer->Body = $params['body'];
if ($params['html'])
$mailer->isHTML(true);
if (qa_opt('smtp_active')) {
$mailer->isSMTP();
$mailer->Host = qa_opt('smtp_address');
$mailer->Port = qa_opt('smtp_port');
if (qa_opt('smtp_secure')) {
$mailer->SMTPSecure = qa_opt('smtp_secure');
} else {
$mailer->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
),
);
}
$send_status = $mailer->send();
if(!$send_status){
@error_log('PHP Question2Answer email send error: '.$mailer->ErrorInfo);
if (qa_opt('smtp_authenticate')) {
$mailer->SMTPAuth = true;
$mailer->Username = qa_opt('smtp_username');
$mailer->Password = qa_opt('smtp_password');
}
return $send_status;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
$send_status = $mailer->send();
if (!$send_status) {
@error_log('PHP Question2Answer email send error: ' . $mailer->ErrorInfo);
}
return $send_status;
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-app-events.php
Description: Handles the submission of events to the database (application level)
......@@ -20,69 +19,82 @@
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../../');
exit;
}
require_once QA_INCLUDE_DIR . 'db/events.php';
require_once QA_INCLUDE_DIR . 'app/updates.php';
/**
* Add appropriate events to the database for an action performed on a question. The event of type $updatetype relates
* to $lastpostid whose antecedent question is $questionid, and was caused by $lastuserid. Pass a unix $timestamp for
* the event time or leave as null to use now. This will add an event to $questionid's and $lastuserid's streams. If
* $otheruserid is set, it will also add an notification-style event for that user, unless they are the one who did it.
* @param $questionid
* @param $lastpostid
* @param $updatetype
* @param $lastuserid
* @param $otheruserid
* @param $timestamp
*/
function qa_create_event_for_q_user($questionid, $lastpostid, $updatetype, $lastuserid, $otheruserid = null, $timestamp = null)
{
qa_db_event_create_for_entity(QA_ENTITY_QUESTION, $questionid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // anyone who favorited the question
if (isset($lastuserid) && !QA_FINAL_EXTERNAL_USERS)
qa_db_event_create_for_entity(QA_ENTITY_USER, $lastuserid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // anyone who favorited the user who did it
if (isset($otheruserid) && ($otheruserid != $lastuserid))
qa_db_event_create_not_entity($otheruserid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // possible other user to be informed
}
/**
* Add appropriate events to the database for an action performed on a set of tags in $tagstring (namely, a question
* being created with those tags or having one of those tags added afterwards). The event of type $updatetype relates
* to the question $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the event time or leave as
* null to use now.
* @param $tagstring
* @param $questionid
* @param $updatetype
* @param $lastuserid
* @param $timestamp
*/
function qa_create_event_for_tags($tagstring, $questionid, $updatetype, $lastuserid, $timestamp = null)
{
require_once QA_INCLUDE_DIR . 'util/string.php';
require_once QA_INCLUDE_DIR . 'db/post-create.php';
$tagwordids = qa_db_word_mapto_ids(array_unique(qa_tagstring_to_tags($tagstring)));
foreach ($tagwordids as $wordid) {
qa_db_event_create_for_entity(QA_ENTITY_TAG, $wordid, $questionid, $questionid, $updatetype, $lastuserid, $timestamp);
}
require_once QA_INCLUDE_DIR.'db/events.php';
require_once QA_INCLUDE_DIR.'app/updates.php';
function qa_create_event_for_q_user($questionid, $lastpostid, $updatetype, $lastuserid, $otheruserid=null, $timestamp=null)
/*
Add appropriate events to the database for an action performed on a question. The event of type $updatetype relates
to $lastpostid whose antecedent question is $questionid, and was caused by $lastuserid. Pass a unix $timestamp for
the event time or leave as null to use now. This will add an event to $questionid's and $lastuserid's streams. If
$otheruserid is set, it will also add an notification-style event for that user, unless they are the one who did it.
*/
{
qa_db_event_create_for_entity(QA_ENTITY_QUESTION, $questionid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // anyone who favorited the question
if (isset($lastuserid) && !QA_FINAL_EXTERNAL_USERS)
qa_db_event_create_for_entity(QA_ENTITY_USER, $lastuserid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // anyone who favorited the user who did it
if (isset($otheruserid) && ($otheruserid!=$lastuserid))
qa_db_event_create_not_entity($otheruserid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // possible other user to be informed
}
function qa_create_event_for_tags($tagstring, $questionid, $updatetype, $lastuserid, $timestamp=null)
/*
Add appropriate events to the database for an action performed on a set of tags in $tagstring (namely, a question
being created with those tags or having one of those tags added afterwards). The event of type $updatetype relates
to the question $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the event time or leave as
null to use now.
*/
{
require_once QA_INCLUDE_DIR.'util/string.php';
require_once QA_INCLUDE_DIR.'db/post-create.php';
$tagwordids=qa_db_word_mapto_ids(array_unique(qa_tagstring_to_tags($tagstring)));
foreach ($tagwordids as $wordid)
qa_db_event_create_for_entity(QA_ENTITY_TAG, $wordid, $questionid, $questionid, $updatetype, $lastuserid, $timestamp);
}
function qa_create_event_for_category($categoryid, $questionid, $updatetype, $lastuserid, $timestamp=null)
/*
Add appropriate events to the database for an action performed on $categoryid (namely, a question being created in
that category or being moved to it later on), along with all of its ancestor categories. The event of type
$updatetype relates to the question $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the event
time or leave as null to use now.
*/
{
if (isset($categoryid)) {
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'app/format.php';
$categories=qa_category_path(qa_db_single_select(qa_db_category_nav_selectspec($categoryid, true)), $categoryid);
foreach ($categories as $category)
qa_db_event_create_for_entity(QA_ENTITY_CATEGORY, $category['categoryid'], $questionid, $questionid, $updatetype, $lastuserid, $timestamp);
}
/**
* Add appropriate events to the database for an action performed on $categoryid (namely, a question being created in
* that category or being moved to it later on), along with all of its ancestor categories. The event of type
* $updatetype relates to the question $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the event
* time or leave as null to use now.
* @param $categoryid
* @param $questionid
* @param $updatetype
* @param $lastuserid
* @param $timestamp
*/
function qa_create_event_for_category($categoryid, $questionid, $updatetype, $lastuserid, $timestamp = null)
{
if (isset($categoryid)) {
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
$categories = qa_category_path(qa_db_single_select(qa_db_category_nav_selectspec($categoryid, true)), $categoryid);
foreach ($categories as $category) {
qa_db_event_create_for_entity(QA_ENTITY_CATEGORY, $category['categoryid'], $questionid, $questionid, $updatetype, $lastuserid, $timestamp);
}
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
}
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-app-mailing.php
Description: Functions for sending a mailing to all users
......@@ -20,133 +19,138 @@
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../../');
exit;
}
function qa_mailing_start()
/*
Start a mailing to all users, unless one has already been started
*/
{
require_once QA_INCLUDE_DIR.'db/admin.php';
if (strlen(qa_opt('mailing_last_userid'))==0) {
qa_opt('mailing_last_timestamp', time());
qa_opt('mailing_last_userid', '0');
qa_opt('mailing_total_users', qa_db_count_users());
qa_opt('mailing_done_users', 0);
}
}
/**
* Start a mailing to all users, unless one has already been started
*/
function qa_mailing_start()
{
require_once QA_INCLUDE_DIR . 'db/admin.php';
function qa_mailing_stop()
/*
Stop a mailing to all users
*/
{
qa_opt('mailing_last_timestamp', '');
qa_opt('mailing_last_userid', '');
qa_opt('mailing_done_users', '');
qa_opt('mailing_total_users', '');
if (strlen(qa_opt('mailing_last_userid')) == 0) {
qa_opt('mailing_last_timestamp', time());
qa_opt('mailing_last_userid', '0');
qa_opt('mailing_total_users', qa_db_count_users());
qa_opt('mailing_done_users', 0);
}
}
function qa_mailing_perform_step()
/*
Allow the mailing to proceed forwards, for the appropriate amount of time and users, based on the options
*/
{
require_once QA_INCLUDE_DIR.'db/users.php';
/**
* Stop a mailing to all users
*/
function qa_mailing_stop()
{
qa_opt('mailing_last_timestamp', '');
qa_opt('mailing_last_userid', '');
qa_opt('mailing_done_users', '');
qa_opt('mailing_total_users', '');
}
$lastuserid=qa_opt('mailing_last_userid');
if (strlen($lastuserid)) {
$thistime=time();
$lasttime=qa_opt('mailing_last_timestamp');
$perminute=qa_opt('mailing_per_minute');
/**
* Allow the mailing to proceed forwards, for the appropriate amount of time and users, based on the options
*/
function qa_mailing_perform_step()
{
require_once QA_INCLUDE_DIR . 'db/users.php';
if (($lasttime-$thistime)>60) // if it's been a while, we assume there hasn't been continuous mailing...
$lasttime=$thistime-1; // ... so only do 1 second's worth
else // otherwise...
$lasttime=max($lasttime, $thistime-6); // ... don't do more than 6 seconds' worth
$lastuserid = qa_opt('mailing_last_userid');
$count=min(floor(($thistime-$lasttime)*$perminute/60), 100); // don't do more than 100 messages at a time
if (strlen($lastuserid)) {
$thistime = time();
$lasttime = qa_opt('mailing_last_timestamp');
$perminute = qa_opt('mailing_per_minute');
if ($count>0) {
qa_opt('mailing_last_timestamp', $thistime+30);
// prevents a parallel call to qa_mailing_perform_step() from sending messages, unless we're very unlucky with timing (poor man's mutex)
if (($lasttime - $thistime) > 60) // if it's been a while, we assume there hasn't been continuous mailing...
$lasttime = $thistime - 1; // ... so only do 1 second's worth
else // otherwise...
$lasttime = max($lasttime, $thistime - 6); // ... don't do more than 6 seconds' worth
$sentusers=0;
$users=qa_db_users_get_mailing_next($lastuserid, $count);
$count = min(floor(($thistime - $lasttime) * $perminute / 60), 100); // don't do more than 100 messages at a time
if (count($users)) {
foreach ($users as $user)
$lastuserid=max($lastuserid, $user['userid']);
if ($count > 0) {
qa_opt('mailing_last_timestamp', $thistime + 30);
// prevents a parallel call to qa_mailing_perform_step() from sending messages, unless we're very unlucky with timing (poor man's mutex)
qa_opt('mailing_last_userid', $lastuserid);
qa_opt('mailing_done_users', qa_opt('mailing_done_users')+count($users));
$sentusers = 0;
$users = qa_db_users_get_mailing_next($lastuserid, $count);
foreach ($users as $user)
if (!($user['flags'] & QA_USER_FLAGS_NO_MAILINGS)) {
qa_mailing_send_one($user['userid'], $user['handle'], $user['email'], $user['emailcode']);
$sentusers++;
}
if (count($users)) {
foreach ($users as $user) {
$lastuserid = max($lastuserid, $user['userid']);
}
qa_opt('mailing_last_timestamp', $lasttime+$sentusers*60/$perminute); // can be floating point result, based on number of mails actually sent
qa_opt('mailing_last_userid', $lastuserid);
qa_opt('mailing_done_users', qa_opt('mailing_done_users') + count($users));
} else
qa_mailing_stop();
}
}
}
foreach ($users as $user) {
if (!($user['flags'] & QA_USER_FLAGS_NO_MAILINGS)) {
qa_mailing_send_one($user['userid'], $user['handle'], $user['email'], $user['emailcode']);
$sentusers++;
}
}
qa_opt('mailing_last_timestamp', $lasttime + $sentusers * 60 / $perminute); // can be floating point result, based on number of mails actually sent
function qa_mailing_send_one($userid, $handle, $email, $emailcode)
/*
Send a single message from the mailing, to $userid with $handle and $email.
Pass the user's existing $emailcode if there is one, otherwise a new one will be set up
*/
{
require_once QA_INCLUDE_DIR.'app/emails.php';
require_once QA_INCLUDE_DIR.'db/users.php';
if (!strlen(trim($emailcode))) {
$emailcode=qa_db_user_rand_emailcode();
qa_db_user_set($userid, 'emailcode', $emailcode);
} else
qa_mailing_stop();
}
$unsubscribeurl=qa_path_absolute('unsubscribe', array('c' => $emailcode, 'u' => $handle));
return qa_send_email(array(
'fromemail' => qa_opt('mailing_from_email'),
'fromname' => qa_opt('mailing_from_name'),
'toemail' => $email,
'toname' => $handle,
'subject' => qa_opt('mailing_subject'),
'body' => trim(qa_opt('mailing_body'))."\n\n\n".qa_lang('users/unsubscribe').' '.$unsubscribeurl,
'html' => false,
));
}
function qa_mailing_progress_message()
/*
Return a message describing current progress in the mailing
*/
{
if (strlen(qa_opt('mailing_last_userid')))
return strtr(qa_lang('admin/mailing_progress'), array(
'^1' => number_format(qa_opt('mailing_done_users')),
'^2' => number_format(qa_opt('mailing_total_users')),
));
else
return null;
}
/**
* Send a single message from the mailing, to $userid with $handle and $email.
* Pass the user's existing $emailcode if there is one, otherwise a new one will be set up
* @param $userid
* @param $handle
* @param $email
* @param $emailcode
* @return bool
*/
function qa_mailing_send_one($userid, $handle, $email, $emailcode)
{
require_once QA_INCLUDE_DIR . 'app/emails.php';
require_once QA_INCLUDE_DIR . 'db/users.php';
if (!strlen(trim($emailcode))) {
$emailcode = qa_db_user_rand_emailcode();
qa_db_user_set($userid, 'emailcode', $emailcode);
}
$unsubscribeurl = qa_path_absolute('unsubscribe', array('c' => $emailcode, 'u' => $handle));
return qa_send_email(array(
'fromemail' => qa_opt('mailing_from_email'),
'fromname' => qa_opt('mailing_from_name'),
'toemail' => $email,
'toname' => $handle,
'subject' => qa_opt('mailing_subject'),
'body' => trim(qa_opt('mailing_body')) . "\n\n\n" . qa_lang('users/unsubscribe') . ' ' . $unsubscribeurl,
'html' => false,
));
}
/**
* Return a message describing current progress in the mailing
*/
function qa_mailing_progress_message()
{
require_once QA_INCLUDE_DIR . 'app/format.php';
if (strlen(qa_opt('mailing_last_userid'))) {
return strtr(qa_lang('admin/mailing_progress'), array(
'^1' => qa_format_number(qa_opt('mailing_done_users')),
'^2' => qa_format_number(qa_opt('mailing_total_users')),
));
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
return null;
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-app-search.php
Description: Wrapper functions and utilities for search modules
......@@ -20,121 +19,122 @@
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../../');
exit;
}
/**
* Returns $count search results for $query performed by $userid, starting at offset $start. Set $absoluteurls to true
* to get absolute URLs for the results and $fullcontent if the results should include full post content. This calls
* through to the chosen search module, and performs all the necessary post-processing to supplement the results for
* display online or in an RSS feed.
* @param $query
* @param $start
* @param $count
* @param $userid
* @param $absoluteurls
* @param $fullcontent
* @return
*/
function qa_get_search_results($query, $start, $count, $userid, $absoluteurls, $fullcontent)
{
// Identify which search module should be used
$searchmodules = qa_load_modules_with('search', 'process_search');
if (!count($searchmodules))
qa_fatal_error('No search engine is available');
$module = reset($searchmodules); // use first one by default
if (count($searchmodules) > 1) {
$tryname = qa_opt('search_module'); // use chosen one if it's available
if (isset($searchmodules[$tryname]))
$module = $searchmodules[$tryname];
}
// Get the results
function qa_get_search_results($query, $start, $count, $userid, $absoluteurls, $fullcontent)
/*
Returns $count search results for $query performed by $userid, starting at offset $start. Set $absoluteurls to true
to get absolute URLs for the results and $fullcontent if the results should include full post content. This calls
through to the chosen search module, and performs all the necessary post-processing to supplement the results for
display online or in an RSS feed.
*/
{
$results = $module->process_search($query, $start, $count, $userid, $absoluteurls, $fullcontent);
// Identify which search module should be used
// Work out what additional information (if any) we need to retrieve for the results
$searchmodules=qa_load_modules_with('search', 'process_search');
$keypostidgetfull = array();
$keypostidgettype = array();
$keypostidgetquestion = array();
$keypageidgetpage = array();
if (!count($searchmodules))
qa_fatal_error('No search engine is available');
foreach ($results as $result) {
if (isset($result['question_postid']) && !isset($result['question']))
$keypostidgetfull[$result['question_postid']] = true;
$module=reset($searchmodules); // use first one by default
if (isset($result['match_postid'])) {
if (!((isset($result['question_postid'])) || (isset($result['question']))))
$keypostidgetquestion[$result['match_postid']] = true; // we can also get $result['match_type'] from this
if (count($searchmodules)>1) {
$tryname=qa_opt('search_module'); // use chosen one if it's available
if (isset($searchmodules[$tryname]))
$module=$searchmodules[$tryname];
elseif (!isset($result['match_type']))
$keypostidgettype[$result['match_postid']] = true;
}
// Get the results
if (isset($result['page_pageid']) && !isset($result['page']))
$keypageidgetpage[$result['page_pageid']] = true;
}
$results=$module->process_search($query, $start, $count, $userid, $absoluteurls, $fullcontent);
// Perform the appropriate database queries
// Work out what additional information (if any) we need to retrieve for the results
list($postidfull, $postidtype, $postidquestion, $pageidpage) = qa_db_select_with_pending(
count($keypostidgetfull) ? qa_db_posts_selectspec($userid, array_keys($keypostidgetfull), $fullcontent) : null,
count($keypostidgettype) ? qa_db_posts_basetype_selectspec(array_keys($keypostidgettype)) : null,
count($keypostidgetquestion) ? qa_db_posts_to_qs_selectspec($userid, array_keys($keypostidgetquestion), $fullcontent) : null,
count($keypageidgetpage) ? qa_db_pages_selectspec(null, array_keys($keypageidgetpage)) : null
);
$keypostidgetfull=array();
$keypostidgettype=array();
$keypostidgetquestion=array();
$keypageidgetpage=array();
// Supplement the results as appropriate
foreach ($results as $result) {
if (isset($result['question_postid']) && !isset($result['question']))
$keypostidgetfull[$result['question_postid']]=true;
foreach ($results as $key => $result) {
if (isset($result['question_postid']) && !isset($result['question']))
if (@$postidfull[$result['question_postid']]['basetype'] == 'Q')
$result['question'] = @$postidfull[$result['question_postid']];
if (isset($result['match_postid'])) {
if (!( (isset($result['question_postid'])) || (isset($result['question'])) ))
$keypostidgetquestion[$result['match_postid']]=true; // we can also get $result['match_type'] from this
if (isset($result['match_postid'])) {
if (!(isset($result['question_postid']) || isset($result['question']))) {
$result['question'] = @$postidquestion[$result['match_postid']];
elseif (!isset($result['match_type']))
$keypostidgettype[$result['match_postid']]=true;
}
if (!isset($result['match_type']))
$result['match_type'] = @$result['question']['obasetype'];
if (isset($result['page_pageid']) && !isset($result['page']))
$keypageidgetpage[$result['page_pageid']]=true;
} elseif (!isset($result['match_type']))
$result['match_type'] = @$postidtype[$result['match_postid']];
}
// Perform the appropriate database queries
list($postidfull, $postidtype, $postidquestion, $pageidpage)=qa_db_select_with_pending(
count($keypostidgetfull) ? qa_db_posts_selectspec($userid, array_keys($keypostidgetfull), $fullcontent) : null,
count($keypostidgettype) ? qa_db_posts_basetype_selectspec(array_keys($keypostidgettype)) : null,
count($keypostidgetquestion) ? qa_db_posts_to_qs_selectspec($userid, array_keys($keypostidgetquestion), $fullcontent) : null,
count($keypageidgetpage) ? qa_db_pages_selectspec(null, array_keys($keypageidgetpage)) : null
);
// Supplement the results as appropriate
foreach ($results as $key => $result) {
if (isset($result['question_postid']) && !isset($result['question']))
if (@$postidfull[$result['question_postid']]['basetype']=='Q')
$result['question']=@$postidfull[$result['question_postid']];
if (isset($result['match_postid'])) {
if (!( (isset($result['question_postid'])) || (isset($result['question'])) )) {
$result['question']=@$postidquestion[$result['match_postid']];
if (isset($result['question']) && !isset($result['question_postid']))
$result['question_postid'] = $result['question']['postid'];
if (!isset($result['match_type']))
$result['match_type']=@$result['question']['obasetype'];
if (isset($result['page_pageid']) && !isset($result['page']))
$result['page'] = @$pageidpage[$result['page_pageid']];
} elseif (!isset($result['match_type']))
$result['match_type']=@$postidtype[$result['match_postid']];
}
if (isset($result['question']) && !isset($result['question_postid']))
$result['question_postid']=$result['question']['postid'];
if (isset($result['page_pageid']) && !isset($result['page']))
$result['page']=@$pageidpage[$result['page_pageid']];
if (!isset($result['title'])) {
if (isset($result['question']))
$result['title']=$result['question']['title'];
elseif (isset($result['page']))
$result['title']=$result['page']['heading'];
}
if (!isset($result['url'])) {
if (isset($result['question']))
$result['url']=qa_q_path($result['question']['postid'], $result['question']['title'],
$absoluteurls, @$result['match_type'], @$result['match_postid']);
elseif (isset($result['page']))
$result['url']=qa_path($result['page']['tags'], null, qa_opt('site_url'));
}
$results[$key]=$result;
if (!isset($result['title'])) {
if (isset($result['question']))
$result['title'] = $result['question']['title'];
elseif (isset($result['page']))
$result['title'] = $result['page']['heading'];
}
// Return the results
if (!isset($result['url'])) {
if (isset($result['question']))
$result['url'] = qa_q_path($result['question']['postid'], $result['question']['title'],
$absoluteurls, @$result['match_type'], @$result['match_postid']);
elseif (isset($result['page']))
$result['url'] = qa_path($result['page']['tags'], null, qa_opt('site_url'));
}
return $results;
$results[$key] = $result;
}
// Return the results
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
return $results;
}
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-app-updates.php
Description: Definitions relating to favorites and updates in the database tables
......@@ -20,39 +19,35 @@
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../../');
exit;
}
// Character codes for the different types of entity that can be followed (entitytype columns)
// Character codes for the different types of entity that can be followed (entitytype columns)
define('QA_ENTITY_QUESTION', 'Q');
define('QA_ENTITY_USER', 'U');
define('QA_ENTITY_TAG', 'T');
define('QA_ENTITY_CATEGORY', 'C');
define('QA_ENTITY_NONE', '-');
define('QA_ENTITY_QUESTION', 'Q');
define('QA_ENTITY_USER', 'U');
define('QA_ENTITY_TAG', 'T');
define('QA_ENTITY_CATEGORY', 'C');
define('QA_ENTITY_NONE', '-');
// Character codes for the different types of updates on a post (updatetype columns)
// Character codes for the different types of updates on a post (updatetype columns)
define('QA_UPDATE_CATEGORY', 'A'); // questions only, category changed
define('QA_UPDATE_CLOSED', 'C'); // questions only, closed or reopened
define('QA_UPDATE_CONTENT', 'E'); // title or content edited
define('QA_UPDATE_PARENT', 'M'); // e.g. comment moved when converting its parent answer to a comment
define('QA_UPDATE_SELECTED', 'S'); // answers only, removed if unselected
define('QA_UPDATE_TAGS', 'T'); // questions only
define('QA_UPDATE_TYPE', 'Y'); // e.g. answer to comment
define('QA_UPDATE_VISIBLE', 'H'); // hidden or reshown
define('QA_UPDATE_CATEGORY', 'A'); // questions only, category changed
define('QA_UPDATE_CLOSED', 'C'); // questions only, closed or reopened
define('QA_UPDATE_CONTENT', 'E'); // title or content edited
define('QA_UPDATE_PARENT', 'M'); // e.g. comment moved when converting its parent answer to a comment
define('QA_UPDATE_SELECTED', 'S'); // answers only, removed if unselected
define('QA_UPDATE_TAGS', 'T'); // questions only
define('QA_UPDATE_TYPE', 'Y'); // e.g. answer to comment
define('QA_UPDATE_VISIBLE', 'H'); // hidden or reshown
// Character codes for types of update that only appear in the streams tables, not on the posts themselves
// Character codes for types of update that only appear in the streams tables, not on the posts themselves
define('QA_UPDATE_FOLLOWS', 'F'); // if a new question was asked related to one of its answers, or for a comment that follows another
define('QA_UPDATE_C_FOR_Q', 'U'); // if comment created was on a question of the user whose stream this appears in
define('QA_UPDATE_C_FOR_A', 'N'); // if comment created was on an answer of the user whose stream this appears in
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
define('QA_UPDATE_FOLLOWS', 'F'); // if a new question was asked related to one of its answers, or for a comment that follows another
define('QA_UPDATE_C_FOR_Q', 'U'); // if comment created was on a question of the user whose stream this appears in
define('QA_UPDATE_C_FOR_A', 'N'); // if comment created was on an answer of the user whose stream this appears in
......@@ -3,7 +3,6 @@
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/qa-db-blobs.php
Description: Database-level access to blobs table for large chunks of data (e.g. images)
......@@ -20,91 +19,103 @@
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
function qa_db_blob_create($content, $format, $sourcefilename=null, $userid=null, $cookieid=null, $ip=null)
/*
Create a new blob in the database with $content and $format, other fields as provided
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
for ($attempt=0; $attempt<10; $attempt++) {
$blobid=qa_db_random_bigint();
if (qa_db_blob_exists($blobid))
continue;
qa_db_query_sub(
'INSERT INTO ^blobs (blobid, format, content, filename, userid, cookieid, createip, created) VALUES (#, $, $, $, $, #, INET_ATON($), NOW())',
$blobid, $format, $content, $sourcefilename, $userid, $cookieid, $ip
);
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../../');
exit;
}
return $blobid;
}
return null;
}
function qa_db_blob_read($blobid)
/*
Get the information about blob $blobid from the database
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
/**
* Create a new blob in the database with $content and $format, other fields as provided
* @param $content
* @param $format
* @param $sourcefilename
* @param $userid
* @param $cookieid
* @param $ip
* @return mixed|null|string
*/
function qa_db_blob_create($content, $format, $sourcefilename = null, $userid = null, $cookieid = null, $ip = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_db_read_one_assoc(qa_db_query_sub(
'SELECT content, format, filename FROM ^blobs WHERE blobid=#',
$blobid
), true);
}
for ($attempt = 0; $attempt < 10; $attempt++) {
$blobid = qa_db_random_bigint();
if (qa_db_blob_exists($blobid))
continue;
function qa_db_blob_set_content($blobid, $content)
/*
Change the content of blob $blobid in the database to $content (can also be null)
*/
{
qa_db_query_sub(
'UPDATE ^blobs SET content=$ WHERE blobid=#',
$content, $blobid
'INSERT INTO ^blobs (blobid, format, content, filename, userid, cookieid, createip, created) VALUES (#, $, $, $, $, #, UNHEX($), NOW())',
$blobid, $format, $content, $sourcefilename, $userid, $cookieid, bin2hex(@inet_pton($ip))
);
}
function qa_db_blob_delete($blobid)
/*
Delete blob $blobid in the database
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
qa_db_query_sub(
'DELETE FROM ^blobs WHERE blobid=#',
$blobid
);
return $blobid;
}
function qa_db_blob_exists($blobid)
/*
Check if blob $blobid exists in the database
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^blobs WHERE blobid=#',
$blobid
)) > 0;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
return null;
}
/**
* Get the information about blob $blobid from the database
* @param $blobid
* @return array|mixed|null
*/
function qa_db_blob_read($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_db_read_one_assoc(qa_db_query_sub(
'SELECT content, format, filename FROM ^blobs WHERE blobid=#',
$blobid
), true);
}
/**
* Change the content of blob $blobid in the database to $content (can also be null)
* @param $blobid
* @param $content
*/
function qa_db_blob_set_content($blobid, $content)
{
qa_db_query_sub(
'UPDATE ^blobs SET content=$ WHERE blobid=#',
$content, $blobid
);
}
/**
* Delete blob $blobid in the database
* @param $blobid
* @return mixed
*/
function qa_db_blob_delete($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
qa_db_query_sub(
'DELETE FROM ^blobs WHERE blobid=#',
$blobid
);
}
/**
* Check if blob $blobid exists in the database
* @param $blobid
* @return bool|mixed
*/
function qa_db_blob_exists($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$blob = qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^blobs WHERE blobid=#',
$blobid
));
return $blob > 0;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment