Commit 54ada742 by Scott

Coding style (app/)

parent f24542bb
...@@ -20,82 +20,103 @@ ...@@ -20,82 +20,103 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
function qa_get_blob_url($blobid, $absolute=false) /**
/* * Return the URL which will output $blobid from the database when requested, $absolute or relative
Return the URL which will output $blobid from the database when requested, $absolute or relative * @param $blobid
*/ * @param bool $absolute
{ * @return mixed|string
*/
function qa_get_blob_url($blobid, $absolute = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_path('blob', array('qa_blobid' => $blobid), $absolute ? qa_opt('site_url') : null, QA_URL_FORMAT_PARAMS); return qa_path('blob', array('qa_blobid' => $blobid), $absolute ? qa_opt('site_url') : null, QA_URL_FORMAT_PARAMS);
} }
function qa_get_blob_directory($blobid) /**
/* * Return the full path to the on-disk directory for blob $blobid (subdirectories are named by the first 3 digits of $blobid)
Return the full path to the on-disk directory for blob $blobid (subdirectories are named by the first 3 digits of $blobid) * @param $blobid
*/ * @return mixed|string
{ */
function qa_get_blob_directory($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return rtrim(QA_BLOBS_DIRECTORY, '/').'/'.substr(str_pad($blobid, 20, '0', STR_PAD_LEFT), 0, 3); return rtrim(QA_BLOBS_DIRECTORY, '/') . '/' . substr(str_pad($blobid, 20, '0', STR_PAD_LEFT), 0, 3);
} }
function qa_get_blob_filename($blobid, $format) /**
/* * Return the full page and filename of blob $blobid which is in $format ($format is used as the file name suffix e.g. .jpg)
Return the full page and filename of blob $blobid which is in $format ($format is used as the file name suffix e.g. .jpg) * @param $blobid
*/ * @param $format
{ * @return mixed|string
*/
function qa_get_blob_filename($blobid, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_get_blob_directory($blobid).'/'.$blobid.'.'.preg_replace('/[^A-Za-z0-9]/', '', $format); return qa_get_blob_directory($blobid) . '/' . $blobid . '.' . preg_replace('/[^A-Za-z0-9]/', '', $format);
} }
function qa_create_blob($content, $format, $sourcefilename=null, $userid=null, $cookieid=null, $ip=null) /**
/* * Create a new blob (storing the content in the database or on disk as appropriate) with $content and $format, returning its blobid.
Create a new blob (storing the content in the database or on disk as appropriate) with $content and $format, returning its blobid. * Pass the original name of the file uploaded in $sourcefilename and the $userid, $cookieid and $ip of the user creating it
Pass the original name of the file uploaded in $sourcefilename and the $userid, $cookieid and $ip of the user creating it * @param $content
*/ * @param $format
{ * @param $sourcefilename
* @param $userid
* @param $cookieid
* @param $ip
* @return mixed|null|string
*/
function qa_create_blob($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); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/blobs.php'; require_once QA_INCLUDE_DIR . 'db/blobs.php';
$blobid=qa_db_blob_create(defined('QA_BLOBS_DIRECTORY') ? null : $content, $format, $sourcefilename, $userid, $cookieid, $ip); $blobid = qa_db_blob_create(defined('QA_BLOBS_DIRECTORY') ? null : $content, $format, $sourcefilename, $userid, $cookieid, $ip);
if (isset($blobid) && defined('QA_BLOBS_DIRECTORY')) if (isset($blobid) && defined('QA_BLOBS_DIRECTORY')) {
// still write content to the database if writing to disk failed
if (!qa_write_blob_file($blobid, $content, $format)) if (!qa_write_blob_file($blobid, $content, $format))
qa_db_blob_set_content($blobid, $content); // still write content to the database if writing to disk failed qa_db_blob_set_content($blobid, $content);
return $blobid;
} }
return $blobid;
function qa_write_blob_file($blobid, $content, $format) }
/*
Write the on-disk file for blob $blobid with $content and $format. Returns true if the write succeeded, false otherwise.
*/ /**
{ * Write the on-disk file for blob $blobid with $content and $format. Returns true if the write succeeded, false otherwise.
* @param $blobid
* @param $content
* @param $format
* @return bool|mixed
*/
function qa_write_blob_file($blobid, $content, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$written=false; $written = false;
$directory=qa_get_blob_directory($blobid); $directory = qa_get_blob_directory($blobid);
if (is_dir($directory) || mkdir($directory, fileperms(rtrim(QA_BLOBS_DIRECTORY, '/')) & 0777)) { if (is_dir($directory) || mkdir($directory, fileperms(rtrim(QA_BLOBS_DIRECTORY, '/')) & 0777)) {
$filename=qa_get_blob_filename($blobid, $format); $filename = qa_get_blob_filename($blobid, $format);
$file=fopen($filename, 'xb'); $file = fopen($filename, 'xb');
if (is_resource($file)) { if (is_resource($file)) {
if (fwrite($file, $content)>=strlen($content)) if (fwrite($file, $content) >= strlen($content))
$written=true; $written = true;
fclose($file); fclose($file);
...@@ -105,32 +126,37 @@ ...@@ -105,32 +126,37 @@
} }
return $written; return $written;
} }
function qa_read_blob($blobid) /**
/* * Retrieve blob $blobid from the database, reading the content from disk if appropriate
Retrieve blob $blobid from the database, reading the content from disk if appropriate * @param $blobid
*/ * @return array|mixed|null
{ */
function qa_read_blob($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/blobs.php'; require_once QA_INCLUDE_DIR . 'db/blobs.php';
$blob=qa_db_blob_read($blobid); $blob = qa_db_blob_read($blobid);
if (isset($blob) && defined('QA_BLOBS_DIRECTORY') && !isset($blob['content'])) if (isset($blob) && defined('QA_BLOBS_DIRECTORY') && !isset($blob['content']))
$blob['content']=qa_read_blob_file($blobid, $blob['format']); $blob['content'] = qa_read_blob_file($blobid, $blob['format']);
return $blob; return $blob;
} }
function qa_read_blob_file($blobid, $format) /**
/* * Read the content of blob $blobid in $format from disk. On failure, it will return false.
Read the content of blob $blobid in $format from disk. On failure, it will return false. * @param $blobid
*/ * @param $format
{ * @return mixed|null|string
*/
function qa_read_blob_file($blobid, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$filename = qa_get_blob_filename($blobid, $format); $filename = qa_get_blob_filename($blobid, $format);
...@@ -138,53 +164,55 @@ ...@@ -138,53 +164,55 @@
return file_get_contents($filename); return file_get_contents($filename);
else else
return null; return null;
} }
function qa_delete_blob($blobid) /**
/* * Delete blob $blobid from the database, and remove the on-disk file if appropriate
Delete blob $blobid from the database, and remove the on-disk file if appropriate * @param $blobid
*/ * @return mixed
{ */
function qa_delete_blob($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/blobs.php'; require_once QA_INCLUDE_DIR . 'db/blobs.php';
if (defined('QA_BLOBS_DIRECTORY')) { if (defined('QA_BLOBS_DIRECTORY')) {
$blob=qa_db_blob_read($blobid); $blob = qa_db_blob_read($blobid);
if (isset($blob) && !isset($blob['content'])) if (isset($blob) && !isset($blob['content']))
unlink(qa_get_blob_filename($blobid, $blob['format'])); unlink(qa_get_blob_filename($blobid, $blob['format']));
} }
qa_db_blob_delete($blobid); qa_db_blob_delete($blobid);
} }
function qa_delete_blob_file($blobid, $format) /**
/* * Delete the on-disk file for blob $blobid in $format
Delete the on-disk file for blob $blobid in $format * @param $blobid
*/ * @param $format
{ * @return mixed
*/
function qa_delete_blob_file($blobid, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
unlink(qa_get_blob_filename($blobid, $format)); unlink(qa_get_blob_filename($blobid, $format));
} }
function qa_blob_exists($blobid) /**
/* * Check if blob $blobid exists
Check if blob $blobid exists * @param $blobid
*/ * @return bool|mixed
{ */
function qa_blob_exists($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/blobs.php'; require_once QA_INCLUDE_DIR . 'db/blobs.php';
return qa_db_blob_exists($blobid); return qa_db_blob_exists($blobid);
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -39,6 +39,8 @@ function qa_captcha_available() ...@@ -39,6 +39,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 * 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) function qa_captcha_reason_note($captchareason)
{ {
...@@ -65,8 +67,13 @@ function qa_captcha_reason_note($captchareason) ...@@ -65,8 +67,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. * 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). * 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()) if (!qa_captcha_available())
return ''; return '';
...@@ -79,8 +86,7 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null) ...@@ -79,8 +86,7 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null)
if ($count > 1) { if ($count > 1) {
// use blank captcha in order to load via JS // use blank captcha in order to load via JS
$html = ''; $html = '';
} } else {
else {
// first captcha is always loaded explicitly // first captcha is always loaded explicitly
$qa_content['script_var']['qa_captcha_in'] = 'qa_captcha_div_1'; $qa_content['script_var']['qa_captcha_in'] = 'qa_captcha_div_1';
$html = $captcha->form_html($qa_content, @$errors['captcha']); $html = $captcha->form_html($qa_content, @$errors['captcha']);
...@@ -89,17 +95,19 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null) ...@@ -89,17 +95,19 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null)
$fields['captcha'] = array( $fields['captcha'] = array(
'type' => 'custom', 'type' => 'custom',
'label' => qa_lang_html('misc/captcha_label'), '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, 'error' => @array_key_exists('captcha', $errors) ? qa_lang_html('misc/captcha_error') : null,
'note' => $note, '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. * 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) function qa_captcha_validate_post(&$errors)
{ {
......
...@@ -20,59 +20,56 @@ ...@@ -20,59 +20,56 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
function qa_cookie_get() /**
/* * Return the user identification cookie sent by the browser for this page request, or null if none
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); } 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; return isset($_COOKIE['qa_id']) ? qa_gpc_to_string($_COOKIE['qa_id']) : null;
} }
function qa_cookie_get_create() /**
/* * Return user identification cookie sent by browser if valid, or create a new one if not.
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)
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 (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/cookies.php'; require_once QA_INCLUDE_DIR . 'db/cookies.php';
$cookieid=qa_cookie_get(); $cookieid = qa_cookie_get();
if (isset($cookieid) && qa_db_cookie_exists($cookieid)) if (!isset($cookieid) || !qa_db_cookie_exists($cookieid)) {
; // cookie is valid // cookie is invalid
else $cookieid = qa_db_cookie_create(qa_remote_ip_address());
$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); setcookie('qa_id', $cookieid, time() + 86400 * 365, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true);
$_COOKIE['qa_id']=$cookieid; $_COOKIE['qa_id'] = $cookieid;
return $cookieid; return $cookieid;
} }
function qa_cookie_report_action($cookieid, $action) /**
/* * Called after a database write $action performed by a user identified by $cookieid,
Called after a database write $action performed by a user identified by $cookieid, * relating to $questionid, $answerid and/or $commentid
relating to $questionid, $answerid and/or $commentid * @param $cookieid
*/ * @param $action
{ */
require_once QA_INCLUDE_DIR.'db/cookies.php'; function qa_cookie_report_action($cookieid, $action)
{
require_once QA_INCLUDE_DIR . 'db/cookies.php';
qa_db_cookie_written($cookieid, qa_remote_ip_address()); qa_db_cookie_written($cookieid, qa_remote_ip_address());
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
...@@ -20,59 +20,68 @@ ...@@ -20,59 +20,68 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
require_once QA_INCLUDE_DIR.'app/options.php'; require_once QA_INCLUDE_DIR . 'app/options.php';
function qa_suspend_notifications($suspend=true) /**
/* * Suspend the sending of all email notifications via qa_send_notification(...) if $suspend is true, otherwise
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.
reinstate it. A counter is kept to allow multiple calls. * @param bool $suspend
*/ */
{ function qa_suspend_notifications($suspend = true)
{
global $qa_notifications_suspended; global $qa_notifications_suspended;
$qa_notifications_suspended+=($suspend ? 1 : -1); $qa_notifications_suspended += ($suspend ? 1 : -1);
} }
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
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
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.
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); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_notifications_suspended; global $qa_notifications_suspended;
if ($qa_notifications_suspended>0) if ($qa_notifications_suspended > 0)
return false; return false;
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR.'util/string.php'; require_once QA_INCLUDE_DIR . 'util/string.php';
if (isset($userid)) { if (isset($userid)) {
$needemail=!qa_email_validate(@$email); // take from user if invalid, e.g. @ used in practice $needemail = !qa_email_validate(@$email); // take from user if invalid, e.g. @ used in practice
$needhandle=empty($handle); $needhandle = empty($handle);
if ($needemail || $needhandle) { if ($needemail || $needhandle) {
if (QA_FINAL_EXTERNAL_USERS) { if (QA_FINAL_EXTERNAL_USERS) {
if ($needhandle) { if ($needhandle) {
$handles=qa_get_public_from_userids(array($userid)); $handles = qa_get_public_from_userids(array($userid));
$handle=@$handles[$userid]; $handle = @$handles[$userid];
} }
if ($needemail) if ($needemail)
$email=qa_get_user_email($userid); $email = qa_get_user_email($userid);
} else { } else {
$useraccount=qa_db_select_with_pending( $useraccount = qa_db_select_with_pending(
array( array(
'columns' => array('email', 'handle'), 'columns' => array('email', 'handle'),
'source' => '^users WHERE userid = #', 'source' => '^users WHERE userid = #',
...@@ -82,20 +91,20 @@ ...@@ -82,20 +91,20 @@
); );
if ($needhandle) if ($needhandle)
$handle=@$useraccount['handle']; $handle = @$useraccount['handle'];
if ($needemail) if ($needemail)
$email=@$useraccount['email']; $email = @$useraccount['email'];
} }
} }
} }
if (isset($email) && qa_email_validate($email)) { if (isset($email) && qa_email_validate($email)) {
$subs['^site_title']=qa_opt('site_title'); $subs['^site_title'] = qa_opt('site_title');
$subs['^handle']=$handle; $subs['^handle'] = $handle;
$subs['^email']=$email; $subs['^email'] = $email;
$subs['^open']="\n"; $subs['^open'] = "\n";
$subs['^close']="\n"; $subs['^close'] = "\n";
return qa_send_email(array( return qa_send_email(array(
'fromemail' => qa_opt('from_email'), 'fromemail' => qa_opt('from_email'),
...@@ -103,76 +112,72 @@ ...@@ -103,76 +112,72 @@
'toemail' => $email, 'toemail' => $email,
'toname' => $handle, 'toname' => $handle,
'subject' => strtr($subject, $subs), 'subject' => strtr($subject, $subs),
'body' => (empty($handle) ? '' : qa_lang_sub('emails/to_handle_prefix', $handle)).strtr($body, $subs), 'body' => (empty($handle) ? '' : qa_lang_sub('emails/to_handle_prefix', $handle)) . strtr($body, $subs),
'html' => $html, 'html' => $html,
)); ));
}
} else
return false; return false;
} }
function qa_send_email($params) /**
/* * Send the email based on the $params array - the following keys are required (some can be empty): fromemail,
Send the email based on the $params array - the following keys are required (some can be empty): fromemail, * fromname, toemail, toname, subject, body, html
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 (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// @error_log(print_r($params, true)); // @error_log(print_r($params, true));
require_once QA_INCLUDE_DIR.'vendor/PHPMailer/PHPMailerAutoload.php'; require_once QA_INCLUDE_DIR . 'vendor/PHPMailer/PHPMailerAutoload.php';
$mailer=new PHPMailer(); $mailer = new PHPMailer();
$mailer->CharSet='utf-8'; $mailer->CharSet = 'utf-8';
$mailer->From=$params['fromemail']; $mailer->From = $params['fromemail'];
$mailer->Sender=$params['fromemail']; $mailer->Sender = $params['fromemail'];
$mailer->FromName=$params['fromname']; $mailer->FromName = $params['fromname'];
$mailer->addAddress($params['toemail'], $params['toname']); $mailer->addAddress($params['toemail'], $params['toname']);
if(!empty($params['replytoemail'])){ if (!empty($params['replytoemail'])) {
$mailer->addReplyTo($params['replytoemail'], $params['replytoname']); $mailer->addReplyTo($params['replytoemail'], $params['replytoname']);
} }
$mailer->Subject=$params['subject']; $mailer->Subject = $params['subject'];
$mailer->Body=$params['body']; $mailer->Body = $params['body'];
if ($params['html']) if ($params['html'])
$mailer->isHTML(true); $mailer->isHTML(true);
if (qa_opt('smtp_active')) { if (qa_opt('smtp_active')) {
$mailer->isSMTP(); $mailer->isSMTP();
$mailer->Host=qa_opt('smtp_address'); $mailer->Host = qa_opt('smtp_address');
$mailer->Port=qa_opt('smtp_port'); $mailer->Port = qa_opt('smtp_port');
if (qa_opt('smtp_secure')){ if (qa_opt('smtp_secure')) {
$mailer->SMTPSecure=qa_opt('smtp_secure'); $mailer->SMTPSecure = qa_opt('smtp_secure');
} } else {
else { $mailer->SMTPOptions = array(
$mailer->SMTPOptions=array(
'ssl' => array( 'ssl' => array(
'verify_peer' => false, 'verify_peer' => false,
'verify_peer_name' => false, 'verify_peer_name' => false,
'allow_self_signed' => true 'allow_self_signed' => true,
) ),
); );
} }
if (qa_opt('smtp_authenticate')) { if (qa_opt('smtp_authenticate')) {
$mailer->SMTPAuth=true; $mailer->SMTPAuth = true;
$mailer->Username=qa_opt('smtp_username'); $mailer->Username = qa_opt('smtp_username');
$mailer->Password=qa_opt('smtp_password'); $mailer->Password = qa_opt('smtp_password');
} }
} }
$send_status = $mailer->send(); $send_status = $mailer->send();
if(!$send_status){ if (!$send_status) {
@error_log('PHP Question2Answer email send error: '.$mailer->ErrorInfo); @error_log('PHP Question2Answer email send error: ' . $mailer->ErrorInfo);
} }
return $send_status; return $send_status;
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
...@@ -20,69 +20,82 @@ ...@@ -20,69 +20,82 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
require_once QA_INCLUDE_DIR.'db/events.php'; require_once QA_INCLUDE_DIR . 'db/events.php';
require_once QA_INCLUDE_DIR.'app/updates.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
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
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
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.
$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 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) 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 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)) if (isset($otheruserid) && ($otheruserid != $lastuserid))
qa_db_event_create_not_entity($otheruserid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // possible other user to be informed 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
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
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
to the question $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the event time or leave as * null to use now.
null to use now. * @param $tagstring
*/ * @param $questionid
{ * @param $updatetype
require_once QA_INCLUDE_DIR.'util/string.php'; * @param $lastuserid
require_once QA_INCLUDE_DIR.'db/post-create.php'; * @param $timestamp
*/
$tagwordids=qa_db_word_mapto_ids(array_unique(qa_tagstring_to_tags($tagstring))); function qa_create_event_for_tags($tagstring, $questionid, $updatetype, $lastuserid, $timestamp = null)
foreach ($tagwordids as $wordid) {
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); 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 * 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 * 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 * $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. * 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)) { if (isset($categoryid)) {
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR.'app/format.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); $categories = qa_category_path(qa_db_single_select(qa_db_category_nav_selectspec($categoryid, true)), $categoryid);
foreach ($categories as $category) foreach ($categories as $category) {
qa_db_event_create_for_entity(QA_ENTITY_CATEGORY, $category['categoryid'], $questionid, $questionid, $updatetype, $lastuserid, $timestamp); 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
...@@ -20,13 +20,13 @@ ...@@ -20,13 +20,13 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
/** /**
* Set an entity to be favorited or removed from favorites. Handles event reporting. * Set an entity to be favorited or removed from favorites. Handles event reporting.
* *
* @param int $userid ID of user assigned to the favorite * @param int $userid ID of user assigned to the favorite
...@@ -36,11 +36,11 @@ ...@@ -36,11 +36,11 @@
* @param string $entityid ID of the entity being favorited (e.g. postid for questions) * @param string $entityid ID of the entity being favorited (e.g. postid for questions)
* @param bool $favorite Whether to add favorite (true) or remove favorite (false) * @param bool $favorite Whether to add favorite (true) or remove favorite (false)
*/ */
function qa_user_favorite_set($userid, $handle, $cookieid, $entitytype, $entityid, $favorite) function qa_user_favorite_set($userid, $handle, $cookieid, $entitytype, $entityid, $favorite)
{ {
require_once QA_INCLUDE_DIR.'db/favorites.php'; require_once QA_INCLUDE_DIR . 'db/favorites.php';
require_once QA_INCLUDE_DIR.'app/limits.php'; require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR.'app/updates.php'; require_once QA_INCLUDE_DIR . 'app/updates.php';
// Make sure the user is not favoriting themselves // Make sure the user is not favoriting themselves
if ($entitytype == QA_ENTITY_USER && $userid == $entityid) { if ($entitytype == QA_ENTITY_USER && $userid == $entityid) {
...@@ -54,23 +54,23 @@ ...@@ -54,23 +54,23 @@
switch ($entitytype) { switch ($entitytype) {
case QA_ENTITY_QUESTION: case QA_ENTITY_QUESTION:
$action=$favorite ? 'q_favorite' : 'q_unfavorite'; $action = $favorite ? 'q_favorite' : 'q_unfavorite';
$params=array('postid' => $entityid); $params = array('postid' => $entityid);
break; break;
case QA_ENTITY_USER: case QA_ENTITY_USER:
$action=$favorite ? 'u_favorite' : 'u_unfavorite'; $action = $favorite ? 'u_favorite' : 'u_unfavorite';
$params=array('userid' => $entityid); $params = array('userid' => $entityid);
break; break;
case QA_ENTITY_TAG: case QA_ENTITY_TAG:
$action=$favorite ? 'tag_favorite' : 'tag_unfavorite'; $action = $favorite ? 'tag_favorite' : 'tag_unfavorite';
$params=array('wordid' => $entityid); $params = array('wordid' => $entityid);
break; break;
case QA_ENTITY_CATEGORY: case QA_ENTITY_CATEGORY:
$action=$favorite ? 'cat_favorite' : 'cat_unfavorite'; $action = $favorite ? 'cat_favorite' : 'cat_unfavorite';
$params=array('categoryid' => $entityid); $params = array('categoryid' => $entityid);
break; break;
default: default:
...@@ -79,15 +79,18 @@ ...@@ -79,15 +79,18 @@
} }
qa_report_event($action, $userid, $handle, $cookieid, $params); qa_report_event($action, $userid, $handle, $cookieid, $params);
} }
function qa_favorite_q_list_view($questions, $usershtml) /**
/* * Returns content to set in $qa_content['q_list'] for a user's favorite $questions. Pre-generated
Returns content to set in $qa_content['q_list'] for a user's favorite $questions. Pre-generated * user HTML in $usershtml.
user HTML in $usershtml. * @param $questions
*/ * @param $usershtml
{ * @return array
*/
function qa_favorite_q_list_view($questions, $usershtml)
{
$q_list = array( $q_list = array(
'qs' => array(), 'qs' => array(),
); );
...@@ -96,7 +99,7 @@ ...@@ -96,7 +99,7 @@
return $q_list; return $q_list;
$q_list['form'] = array( $q_list['form'] = array(
'tags' => 'method="post" action="'.qa_self_html().'"', 'tags' => 'method="post" action="' . qa_self_html() . '"',
'hidden' => array( 'hidden' => array(
'code' => qa_get_form_security_code('vote'), 'code' => qa_get_form_security_code('vote'),
), ),
...@@ -110,24 +113,27 @@ ...@@ -110,24 +113,27 @@
} }
return $q_list; return $q_list;
} }
function qa_favorite_users_view($users, $usershtml) /**
/* * Returns content to set in $qa_content['ranking_users'] for a user's favorite $users. Pre-generated
Returns content to set in $qa_content['ranking_users'] for a user's favorite $users. Pre-generated * user HTML in $usershtml.
user HTML in $usershtml. * @param $users
*/ * @param $usershtml
{ * @return array|null
*/
function qa_favorite_users_view($users, $usershtml)
{
if (QA_FINAL_EXTERNAL_USERS) if (QA_FINAL_EXTERNAL_USERS)
return null; return null;
require_once QA_INCLUDE_DIR.'app/users.php'; require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR.'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
$ranking = array( $ranking = array(
'items' => array(), 'items' => array(),
'rows' => ceil(count($users)/qa_opt('columns_users')), 'rows' => ceil(count($users) / qa_opt('columns_users')),
'type' => 'users', 'type' => 'users',
); );
...@@ -144,20 +150,22 @@ ...@@ -144,20 +150,22 @@
} }
return $ranking; return $ranking;
} }
function qa_favorite_tags_view($tags) /**
/* * Returns content to set in $qa_content['ranking_tags'] for a user's favorite $tags.
Returns content to set in $qa_content['ranking_tags'] for a user's favorite $tags. * @param $tags
*/ * @return array
{ */
require_once QA_INCLUDE_DIR.'app/format.php'; function qa_favorite_tags_view($tags)
{
require_once QA_INCLUDE_DIR . 'app/format.php';
$ranking = array( $ranking = array(
'items' => array(), 'items' => array(),
'rows' => ceil(count($tags)/qa_opt('columns_tags')), 'rows' => ceil(count($tags) / qa_opt('columns_tags')),
'type' => 'tags' 'type' => 'tags',
); );
foreach ($tags as $tag) { foreach ($tags as $tag) {
...@@ -168,15 +176,17 @@ ...@@ -168,15 +176,17 @@
} }
return $ranking; return $ranking;
} }
function qa_favorite_categories_view($categories) /**
/* * Returns content to set in $qa_content['nav_list_categories'] for a user's favorite $categories.
Returns content to set in $qa_content['nav_list_categories'] for a user's favorite $categories. * @param $categories
*/ * @return array
{ */
require_once QA_INCLUDE_DIR.'app/format.php'; function qa_favorite_categories_view($categories)
{
require_once QA_INCLUDE_DIR . 'app/format.php';
$nav_list_categories = array( $nav_list_categories = array(
'nav' => array(), 'nav' => array(),
...@@ -184,24 +194,19 @@ ...@@ -184,24 +194,19 @@
); );
foreach ($categories as $category) { foreach ($categories as $category) {
$cat_url = qa_path_html( 'questions/' . implode( '/', array_reverse(explode('/', $category['backpath'])) ) ); $cat_url = qa_path_html('questions/' . implode('/', array_reverse(explode('/', $category['backpath']))));
$cat_anchor = $category['qcount'] == 1 $cat_anchor = $category['qcount'] == 1
? qa_lang_html_sub('main/1_question', '1', '1') ? qa_lang_html_sub('main/1_question', '1', '1')
: qa_lang_html_sub('main/x_questions', qa_format_number($category['qcount'], 0, true)); : qa_lang_html_sub('main/x_questions', qa_format_number($category['qcount'], 0, true));
$cat_descr = strlen($category['content']) ? qa_html(' - '.$category['content']) : ''; $cat_descr = strlen($category['content']) ? qa_html(' - ' . $category['content']) : '';
$nav_list_categories['nav'][$category['categoryid']] = array( $nav_list_categories['nav'][$category['categoryid']] = array(
'label' => qa_html($category['title']), 'label' => qa_html($category['title']),
'state' => 'open', 'state' => 'open',
'favorited' => true, 'favorited' => true,
'note' => ' - <a href="'.$cat_url.'">'.$cat_anchor.'</a>'.$cat_descr, 'note' => ' - <a href="' . $cat_url . '">' . $cat_anchor . '</a>' . $cat_descr,
); );
} }
return $nav_list_categories; return $nav_list_categories;
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -133,8 +133,8 @@ function qa_limits_calc_remaining($action, $userlimits, $iplimits) ...@@ -133,8 +133,8 @@ function qa_limits_calc_remaining($action, $userlimits, $iplimits)
$period = (int)(qa_opt('db_time') / 3600); $period = (int)(qa_opt('db_time') / 3600);
return max(0, min( return max(0, min(
$usermax - ((@$userlimits['period'] == $period) ? $userlimits['count'] : 0), $usermax - (@$userlimits['period'] == $period ? $userlimits['count'] : 0),
$ipmax - ((@$iplimits['period'] == $period) ? $iplimits['count'] : 0) $ipmax - (@$iplimits['period'] == $period ? $iplimits['count'] : 0)
)); ));
} }
...@@ -229,7 +229,7 @@ function qa_ip_between($ip, $startip, $endip) ...@@ -229,7 +229,7 @@ function qa_ip_between($ip, $startip, $endip)
if (count($uip) != count($ustartip) || count($uip) != count($uendip)) if (count($uip) != count($ustartip) || count($uip) != count($uendip))
return false; return false;
foreach ($uip as $i=>$byte) { foreach ($uip as $i => $byte) {
if ($byte < $ustartip[$i] || $byte > $uendip[$i]) { if ($byte < $ustartip[$i] || $byte > $uendip[$i]) {
return false; return false;
} }
......
...@@ -20,105 +20,112 @@ ...@@ -20,105 +20,112 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
function qa_mailing_start() /**
/* * Start a mailing to all users, unless one has already been started
Start a mailing to all users, unless one has already been started */
*/ function qa_mailing_start()
{ {
require_once QA_INCLUDE_DIR.'db/admin.php'; require_once QA_INCLUDE_DIR . 'db/admin.php';
if (strlen(qa_opt('mailing_last_userid'))==0) { if (strlen(qa_opt('mailing_last_userid')) == 0) {
qa_opt('mailing_last_timestamp', time()); qa_opt('mailing_last_timestamp', time());
qa_opt('mailing_last_userid', '0'); qa_opt('mailing_last_userid', '0');
qa_opt('mailing_total_users', qa_db_count_users()); qa_opt('mailing_total_users', qa_db_count_users());
qa_opt('mailing_done_users', 0); qa_opt('mailing_done_users', 0);
} }
} }
function qa_mailing_stop() /**
/* * Stop a mailing to all users
Stop a mailing to all users */
*/ function qa_mailing_stop()
{ {
qa_opt('mailing_last_timestamp', ''); qa_opt('mailing_last_timestamp', '');
qa_opt('mailing_last_userid', ''); qa_opt('mailing_last_userid', '');
qa_opt('mailing_done_users', ''); qa_opt('mailing_done_users', '');
qa_opt('mailing_total_users', ''); qa_opt('mailing_total_users', '');
} }
function qa_mailing_perform_step() /**
/* * Allow the mailing to proceed forwards, for the appropriate amount of time and users, based on the options
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'; require_once QA_INCLUDE_DIR . 'db/users.php';
$lastuserid=qa_opt('mailing_last_userid'); $lastuserid = qa_opt('mailing_last_userid');
if (strlen($lastuserid)) { if (strlen($lastuserid)) {
$thistime=time(); $thistime = time();
$lasttime=qa_opt('mailing_last_timestamp'); $lasttime = qa_opt('mailing_last_timestamp');
$perminute=qa_opt('mailing_per_minute'); $perminute = qa_opt('mailing_per_minute');
if (($lasttime-$thistime)>60) // if it's been a while, we assume there hasn't been continuous mailing... 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 $lasttime = $thistime - 1; // ... so only do 1 second's worth
else // otherwise... else // otherwise...
$lasttime=max($lasttime, $thistime-6); // ... don't do more than 6 seconds' worth $lasttime = max($lasttime, $thistime - 6); // ... don't do more than 6 seconds' worth
$count=min(floor(($thistime-$lasttime)*$perminute/60), 100); // don't do more than 100 messages at a time $count = min(floor(($thistime - $lasttime) * $perminute / 60), 100); // don't do more than 100 messages at a time
if ($count>0) { if ($count > 0) {
qa_opt('mailing_last_timestamp', $thistime+30); 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) // prevents a parallel call to qa_mailing_perform_step() from sending messages, unless we're very unlucky with timing (poor man's mutex)
$sentusers=0; $sentusers = 0;
$users=qa_db_users_get_mailing_next($lastuserid, $count); $users = qa_db_users_get_mailing_next($lastuserid, $count);
if (count($users)) { if (count($users)) {
foreach ($users as $user) foreach ($users as $user) {
$lastuserid=max($lastuserid, $user['userid']); $lastuserid = max($lastuserid, $user['userid']);
}
qa_opt('mailing_last_userid', $lastuserid); qa_opt('mailing_last_userid', $lastuserid);
qa_opt('mailing_done_users', qa_opt('mailing_done_users')+count($users)); qa_opt('mailing_done_users', qa_opt('mailing_done_users') + count($users));
foreach ($users as $user) foreach ($users as $user) {
if (!($user['flags'] & QA_USER_FLAGS_NO_MAILINGS)) { if (!($user['flags'] & QA_USER_FLAGS_NO_MAILINGS)) {
qa_mailing_send_one($user['userid'], $user['handle'], $user['email'], $user['emailcode']); qa_mailing_send_one($user['userid'], $user['handle'], $user['email'], $user['emailcode']);
$sentusers++; $sentusers++;
} }
}
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_timestamp', $lasttime + $sentusers * 60 / $perminute); // can be floating point result, based on number of mails actually sent
} else } else
qa_mailing_stop(); qa_mailing_stop();
} }
} }
} }
function qa_mailing_send_one($userid, $handle, $email, $emailcode) /**
/* * Send a single message from the mailing, to $userid with $handle and $email.
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
Pass the user's existing $emailcode if there is one, otherwise a new one will be set up * @param $userid
*/ * @param $handle
{ * @param $email
require_once QA_INCLUDE_DIR.'app/emails.php'; * @param $emailcode
require_once QA_INCLUDE_DIR.'db/users.php'; * @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))) { if (!strlen(trim($emailcode))) {
$emailcode=qa_db_user_rand_emailcode(); $emailcode = qa_db_user_rand_emailcode();
qa_db_user_set($userid, 'emailcode', $emailcode); qa_db_user_set($userid, 'emailcode', $emailcode);
} }
$unsubscribeurl=qa_path_absolute('unsubscribe', array('c' => $emailcode, 'u' => $handle)); $unsubscribeurl = qa_path_absolute('unsubscribe', array('c' => $emailcode, 'u' => $handle));
return qa_send_email(array( return qa_send_email(array(
'fromemail' => qa_opt('mailing_from_email'), 'fromemail' => qa_opt('mailing_from_email'),
...@@ -126,29 +133,25 @@ ...@@ -126,29 +133,25 @@
'toemail' => $email, 'toemail' => $email,
'toname' => $handle, 'toname' => $handle,
'subject' => qa_opt('mailing_subject'), 'subject' => qa_opt('mailing_subject'),
'body' => trim(qa_opt('mailing_body'))."\n\n\n".qa_lang('users/unsubscribe').' '.$unsubscribeurl, 'body' => trim(qa_opt('mailing_body')) . "\n\n\n" . qa_lang('users/unsubscribe') . ' ' . $unsubscribeurl,
'html' => false, 'html' => false,
)); ));
} }
function qa_mailing_progress_message() /**
/* * Return a message describing current progress in the mailing
Return a message describing current progress in the mailing */
*/ function qa_mailing_progress_message()
{ {
require_once QA_INCLUDE_DIR . 'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
if (strlen(qa_opt('mailing_last_userid'))) if (strlen(qa_opt('mailing_last_userid'))) {
return strtr(qa_lang('admin/mailing_progress'), array( return strtr(qa_lang('admin/mailing_progress'), array(
'^1' => qa_format_number(qa_opt('mailing_done_users')), '^1' => qa_format_number(qa_opt('mailing_done_users')),
'^2' => qa_format_number(qa_opt('mailing_total_users')), '^2' => qa_format_number(qa_opt('mailing_total_users')),
)); ));
else
return null;
} }
return null;
/* }
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,24 +20,28 @@ ...@@ -20,24 +20,28 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
function qa_wall_error_html($fromuserid, $touserid, $touserflags) /**
/* * Returns an HTML string describing the reason why user $fromuserid cannot post on the wall of $touserid who has
Returns an HTML string describing the reason why user $fromuserid cannot post on the wall of $touserid who has * user flags $touserflags. If there is no such reason the function returns false.
user flags $touserflags. If there is no such reason the function returns false. * @param $fromuserid
*/ * @param $touserid
{ * @param $touserflags
require_once QA_INCLUDE_DIR.'app/limits.php'; * @return bool|mixed|string
*/
function qa_wall_error_html($fromuserid, $touserid, $touserflags)
{
require_once QA_INCLUDE_DIR . 'app/limits.php';
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (!QA_FINAL_EXTERNAL_USERS && qa_opt('allow_user_walls')) { if (!QA_FINAL_EXTERNAL_USERS && qa_opt('allow_user_walls')) {
if ( ($touserflags & QA_USER_FLAGS_NO_WALL_POSTS) && !(isset($fromuserid) && $fromuserid == $touserid) ) if (($touserflags & QA_USER_FLAGS_NO_WALL_POSTS) && !(isset($fromuserid) && $fromuserid == $touserid))
return qa_lang_html('profile/post_wall_blocked'); return qa_lang_html('profile/post_wall_blocked');
else { else {
...@@ -66,19 +70,27 @@ ...@@ -66,19 +70,27 @@
} }
return qa_lang_html('users/no_permission'); return qa_lang_html('users/no_permission');
} }
function qa_wall_add_post($userid, $handle, $cookieid, $touserid, $tohandle, $content, $format) /**
/* * Adds a post to the wall of user $touserid with handle $tohandle, containing $content in $format (e.g. '' for text or 'html')
Adds a post to the wall of user $touserid with handle $tohandle, containing $content in $format (e.g. '' for text or 'html') * The post is by user $userid with handle $handle, and $cookieid is the user's current cookie (used for reporting the event).
The post is by user $userid with handle $handle, and $cookieid is the user's current cookie (used for reporting the event). * @param $userid
*/ * @param $handle
{ * @param $cookieid
* @param $touserid
* @param $tohandle
* @param $content
* @param $format
* @return mixed
*/
function qa_wall_add_post($userid, $handle, $cookieid, $touserid, $tohandle, $content, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR.'db/messages.php'; require_once QA_INCLUDE_DIR . 'db/messages.php';
$messageid = qa_db_message_create($userid, $touserid, $content, $format, true); $messageid = qa_db_message_create($userid, $touserid, $content, $format, true);
qa_db_user_recount_posts($touserid); qa_db_user_recount_posts($touserid);
...@@ -93,16 +105,20 @@ ...@@ -93,16 +105,20 @@
)); ));
return $messageid; return $messageid;
} }
function qa_wall_delete_post($userid, $handle, $cookieid, $message) /**
/* * Deletes the wall post described in $message (as obtained via qa_db_recent_messages_selectspec()). The deletion was performed
Deletes the wall post described in $message (as obtained via qa_db_recent_messages_selectspec()). The deletion was performed * by user $userid with handle $handle, and $cookieid is the user's current cookie (all used for reporting the event).
by user $userid with handle $handle, and $cookieid is the user's current cookie (all used for reporting the event). * @param $userid
*/ * @param $handle
{ * @param $cookieid
require_once QA_INCLUDE_DIR.'db/messages.php'; * @param $message
*/
function qa_wall_delete_post($userid, $handle, $cookieid, $message)
{
require_once QA_INCLUDE_DIR . 'db/messages.php';
qa_db_message_delete($message['messageid']); qa_db_message_delete($message['messageid']);
qa_db_user_recount_posts($message['touserid']); qa_db_user_recount_posts($message['touserid']);
...@@ -111,21 +127,24 @@ ...@@ -111,21 +127,24 @@
'messageid' => $message['messageid'], 'messageid' => $message['messageid'],
'oldmessage' => $message, 'oldmessage' => $message,
)); ));
} }
function qa_wall_posts_add_rules($usermessages, $start) /**
/* * Return the list of messages in $usermessages (as obtained via qa_db_recent_messages_selectspec()) with additional
Return the list of messages in $usermessages (as obtained via qa_db_recent_messages_selectspec()) with additional * fields indicating what actions can be performed on them by the current user. The messages were retrieved beginning
fields indicating what actions can be performed on them by the current user. The messages were retrieved beginning * at offset $start in the database. Currently only 'deleteable' is relevant.
at offset $start in the database. Currently only 'deleteable' is relevant. * @param $usermessages
*/ * @param $start
{ * @return mixed
*/
function qa_wall_posts_add_rules($usermessages, $start)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$userid = qa_get_logged_in_userid(); $userid = qa_get_logged_in_userid();
$userdeleteall = !(qa_user_permit_error('permit_hide_show') || qa_user_permit_error('permit_delete_hidden'));
// reuse "Hiding or showing any post" and "Deleting hidden posts" permissions // reuse "Hiding or showing any post" and "Deleting hidden posts" permissions
$userdeleteall = !(qa_user_permit_error('permit_hide_show') || qa_user_permit_error('permit_delete_hidden'));
$userrecent = $start == 0 && isset($userid); // User can delete all of the recent messages they wrote on someone's wall... $userrecent = $start == 0 && isset($userid); // User can delete all of the recent messages they wrote on someone's wall...
foreach ($usermessages as $key => $message) { foreach ($usermessages as $key => $message) {
...@@ -139,16 +158,18 @@ ...@@ -139,16 +158,18 @@
} }
return $usermessages; return $usermessages;
} }
function qa_wall_post_view($message) /**
/* * Returns an element to add to $qa_content['message_list']['messages'] for $message (as obtained via
Returns an element to add to $qa_content['message_list']['messages'] for $message (as obtained via * qa_db_recent_messages_selectspec() and then qa_wall_posts_add_rules()).
qa_db_recent_messages_selectspec() and then qa_wall_posts_add_rules()). * @param $message
*/ * @return array
{ */
require_once QA_INCLUDE_DIR.'app/format.php'; function qa_wall_post_view($message)
{
require_once QA_INCLUDE_DIR . 'app/format.php';
$options = qa_message_html_defaults(); $options = qa_message_html_defaults();
...@@ -160,7 +181,7 @@ ...@@ -160,7 +181,7 @@
'buttons' => array( 'buttons' => array(
'delete' => array( 'delete' => array(
'tags' => 'name="m'.qa_html($message['messageid']).'_dodelete" onclick="return qa_wall_post_click('.qa_js($message['messageid']).', this);"', 'tags' => 'name="m' . qa_html($message['messageid']) . '_dodelete" onclick="return qa_wall_post_click(' . qa_js($message['messageid']) . ', this);"',
'label' => qa_lang_html('question/delete_button'), 'label' => qa_lang_html('question/delete_button'),
'popup' => qa_lang_html('profile/delete_wall_post_popup'), 'popup' => qa_lang_html('profile/delete_wall_post_popup'),
), ),
...@@ -169,35 +190,38 @@ ...@@ -169,35 +190,38 @@
} }
return $htmlfields; return $htmlfields;
} }
function qa_wall_view_more_link($handle, $start) /**
/* * Returns an element to add to $qa_content['message_list']['messages'] with a link to view all wall posts
Returns an element to add to $qa_content['message_list']['messages'] with a link to view all wall posts * @param $handle
*/ * @param $start
{ * @return array
$url = qa_path_html( 'user/'.$handle.'/wall', array('start' => $start) ); */
function qa_wall_view_more_link($handle, $start)
{
$url = qa_path_html('user/' . $handle . '/wall', array('start' => $start));
return array( return array(
'content' => '<a href="'.$url.'">'.qa_lang_html('profile/wall_view_more').'</a>', 'content' => '<a href="' . $url . '">' . qa_lang_html('profile/wall_view_more') . '</a>',
); );
} }
function qa_pm_delete($userid, $handle, $cookieid, $message, $box) /**
/* * Hides the private message described in $message (as obtained via qa_db_messages_inbox_selectspec() or qa_db_messages_outbox_selectspec()).
Hides the private message described in $message (as obtained via qa_db_messages_inbox_selectspec() or qa_db_messages_outbox_selectspec()). * If both sender and receiver have hidden the message, it gets deleted from the database.
If both sender and receiver have hidden the message, it gets deleted from the database. * Note: currently no event is reported here, so $handle/$cookieid are unused.
Note: currently no event is reported here, so $handle/$cookieid are unused. * @param $userid
*/ * @param $handle
{ * @param $cookieid
require_once QA_INCLUDE_DIR.'db/messages.php'; * @param $message
* @param $box
*/
function qa_pm_delete($userid, $handle, $cookieid, $message, $box)
{
require_once QA_INCLUDE_DIR . 'db/messages.php';
qa_db_message_user_hide($message['messageid'], $box); qa_db_message_user_hide($message['messageid'], $box);
qa_db_message_delete($message['messageid'], false); qa_db_message_delete($message['messageid'], false);
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,33 +20,35 @@ ...@@ -20,33 +20,35 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
require_once QA_INCLUDE_DIR.'db/options.php'; require_once QA_INCLUDE_DIR . 'db/options.php';
define('QA_PERMIT_ALL', 150); define('QA_PERMIT_ALL', 150);
define('QA_PERMIT_USERS', 120); define('QA_PERMIT_USERS', 120);
define('QA_PERMIT_CONFIRMED', 110); define('QA_PERMIT_CONFIRMED', 110);
define('QA_PERMIT_POINTS', 106); define('QA_PERMIT_POINTS', 106);
define('QA_PERMIT_POINTS_CONFIRMED', 104); define('QA_PERMIT_POINTS_CONFIRMED', 104);
define('QA_PERMIT_APPROVED', 103); define('QA_PERMIT_APPROVED', 103);
define('QA_PERMIT_APPROVED_POINTS', 102); define('QA_PERMIT_APPROVED_POINTS', 102);
define('QA_PERMIT_EXPERTS', 100); define('QA_PERMIT_EXPERTS', 100);
define('QA_PERMIT_EDITORS', 70); define('QA_PERMIT_EDITORS', 70);
define('QA_PERMIT_MODERATORS', 40); define('QA_PERMIT_MODERATORS', 40);
define('QA_PERMIT_ADMINS', 20); define('QA_PERMIT_ADMINS', 20);
define('QA_PERMIT_SUPERS', 0); define('QA_PERMIT_SUPERS', 0);
function qa_get_options($names) /**
/* * Return an array [name] => [value] of settings for each option in $names.
Return an array [name] => [value] of settings for each option in $names. * If any options are missing from the database, set them to their defaults
If any options are missing from the database, set them to their defaults * @param $names
*/ * @return array
{ */
function qa_get_options($names)
{
global $qa_options_cache, $qa_options_loaded; global $qa_options_cache, $qa_options_loaded;
// If any options not cached, retrieve them from database via standard pending mechanism // If any options not cached, retrieve them from database via standard pending mechanism
...@@ -55,7 +57,7 @@ ...@@ -55,7 +57,7 @@
qa_preload_options(); qa_preload_options();
if (!$qa_options_loaded) { if (!$qa_options_loaded) {
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
qa_load_options_results(array( qa_load_options_results(array(
qa_db_get_pending_result('options'), qa_db_get_pending_result('options'),
...@@ -65,10 +67,10 @@ ...@@ -65,10 +67,10 @@
// Pull out the options specifically requested here, and assign defaults // Pull out the options specifically requested here, and assign defaults
$options=array(); $options = array();
foreach ($names as $name) { foreach ($names as $name) {
if (!isset($qa_options_cache[$name])) { if (!isset($qa_options_cache[$name])) {
$todatabase=true; $todatabase = true;
switch ($name) { // don't write default to database if option was deprecated, or depends on site language (which could be changed) switch ($name) { // don't write default to database if option was deprecated, or depends on site language (which could be changed)
case 'custom_sidebar': case 'custom_sidebar':
...@@ -78,50 +80,53 @@ ...@@ -78,50 +80,53 @@
case 'ask_needs_login': case 'ask_needs_login':
case 'comment_needs_login': case 'comment_needs_login':
case 'db_time': case 'db_time':
$todatabase=false; $todatabase = false;
break; break;
} }
qa_set_option($name, qa_default_option($name), $todatabase); qa_set_option($name, qa_default_option($name), $todatabase);
} }
$options[$name]=$qa_options_cache[$name]; $options[$name] = $qa_options_cache[$name];
} }
return $options; return $options;
} }
function qa_opt_if_loaded($name) /**
/* * Return the value of option $name if it has already been loaded, otherwise return null
Return the value of option $name if it has already been loaded, otherwise return null * (used to prevent a database query if it's not essential for us to know the option value)
(used to prevent a database query if it's not essential for us to know the option value) * @param $name
*/ * @return
{ */
function qa_opt_if_loaded($name)
{
global $qa_options_cache; global $qa_options_cache;
return @$qa_options_cache[$name]; return @$qa_options_cache[$name];
} }
/** /**
* @deprecated Deprecated since Q2A 1.3 now that all options are retrieved together. * @deprecated Deprecated since Q2A 1.3 now that all options are retrieved together.
* @param $names
*/ */
function qa_options_set_pending($names) function qa_options_set_pending($names)
{ {
} }
function qa_preload_options() /**
/* * Load all of the Q2A options from the database, unless QA_OPTIMIZE_DISTANT_DB is set in qa-config.php,
Load all of the Q2A options from the database, unless QA_OPTIMIZE_DISTANT_DB is set in qa-config.php, * in which case queue the options for later retrieval
in which case queue the options for later retrieval */
*/ function qa_preload_options()
{ {
global $qa_options_loaded; global $qa_options_loaded;
if (!@$qa_options_loaded) { if (!@$qa_options_loaded) {
$selectspecs=array( $selectspecs = array(
'options' => array( 'options' => array(
'columns' => array('title', 'content'), 'columns' => array('title', 'content'),
'source' => '^options', 'source' => '^options',
...@@ -139,32 +144,40 @@ ...@@ -139,32 +144,40 @@
// fetch options in a separate query before everything else // fetch options in a separate query before everything else
qa_load_options_results(qa_db_multi_select($selectspecs)); qa_load_options_results(qa_db_multi_select($selectspecs));
} }
} }
function qa_load_options_results($results) /**
/* * Load the options from the $results of the database selectspecs defined in qa_preload_options()
Load the options from the $results of the database selectspecs defined in qa_preload_options() * @param $results
*/ * @return mixed
{ */
function qa_load_options_results($results)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_options_cache, $qa_options_loaded; global $qa_options_cache, $qa_options_loaded;
foreach ($results as $result) foreach ($results as $result) {
foreach ($result as $name => $value) foreach ($result as $name => $value) {
$qa_options_cache[$name]=$value; $qa_options_cache[$name] = $value;
}
$qa_options_loaded=true;
} }
$qa_options_loaded = true;
}
function qa_set_option($name, $value, $todatabase=true)
/* /**
Set an option $name to $value (application level) in both cache and database, unless * Set an option $name to $value (application level) in both cache and database, unless
$todatabase=false, in which case set it in the cache only * $todatabase=false, in which case set it in the cache only
*/ * @param $name
{ * @param $value
* @param bool $todatabase
* @return mixed
*/
function qa_set_option($name, $value, $todatabase = true)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_options_cache; global $qa_options_cache;
...@@ -172,30 +185,38 @@ ...@@ -172,30 +185,38 @@
if ($todatabase && isset($value)) if ($todatabase && isset($value))
qa_db_set_option($name, $value); qa_db_set_option($name, $value);
$qa_options_cache[$name]=$value; $qa_options_cache[$name] = $value;
} }
function qa_reset_options($names) /**
/* * Reset the options in $names to their defaults
Reset the options in $names to their defaults * @param $names
*/ * @return mixed
{ */
function qa_reset_options($names)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
foreach ($names as $name) foreach ($names as $name) {
qa_set_option($name, qa_default_option($name)); qa_set_option($name, qa_default_option($name));
} }
}
function qa_default_option($name) /**
/* * Return the default value for option $name
Return the default value for option $name * @param $name
*/ * @return bool|mixed|string
{ */
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } function qa_default_option($name)
{
if (qa_to_override(__FUNCTION__)) {
$args = func_get_args();
return qa_call_override(__FUNCTION__, $args);
}
$fixed_defaults=array( $fixed_defaults = array(
'allow_change_usernames' => 1, 'allow_change_usernames' => 1,
'allow_close_questions' => 1, 'allow_close_questions' => 1,
'allow_multi_answers' => 1, 'allow_multi_answers' => 1,
...@@ -363,34 +384,34 @@ ...@@ -363,34 +384,34 @@
'voting_on_qs' => 1, 'voting_on_qs' => 1,
); );
if (isset($fixed_defaults[$name])) if (isset($fixed_defaults[$name])) {
$value=$fixed_defaults[$name]; return $fixed_defaults[$name];
}
else
switch ($name) { switch ($name) {
case 'site_url': case 'site_url':
$value='http://'.@$_SERVER['HTTP_HOST'].strtr(rtrim(dirname($_SERVER['SCRIPT_NAME']), '/'), '\\', '/').'/'; $value = 'http://' . @$_SERVER['HTTP_HOST'] . strtr(rtrim(dirname($_SERVER['SCRIPT_NAME']), '/'), '\\', '/') . '/';
break; break;
case 'site_title': case 'site_title':
$value=qa_default_site_title(); $value = qa_default_site_title();
break; break;
case 'site_theme_mobile': case 'site_theme_mobile':
$value=qa_opt('site_theme'); $value = qa_opt('site_theme');
break; break;
case 'from_email': // heuristic to remove short prefix (e.g. www. or qa.) case 'from_email': // heuristic to remove short prefix (e.g. www. or qa.)
$parts=explode('.', @$_SERVER['HTTP_HOST']); $parts = explode('.', @$_SERVER['HTTP_HOST']);
if ( (count($parts)>2) && (strlen($parts[0])<5) && !is_numeric($parts[0]) ) if ((count($parts) > 2) && (strlen($parts[0]) < 5) && !is_numeric($parts[0]))
unset($parts[0]); unset($parts[0]);
$value='no-reply@'.((count($parts)>1) ? implode('.', $parts) : 'example.com'); $value = 'no-reply@' . ((count($parts) > 1) ? implode('.', $parts) : 'example.com');
break; break;
case 'email_privacy': case 'email_privacy':
$value=qa_lang_html('options/default_privacy'); $value = qa_lang_html('options/default_privacy');
break; break;
case 'show_custom_sidebar': case 'show_custom_sidebar':
...@@ -419,79 +440,79 @@ ...@@ -419,79 +440,79 @@
case 'editor_for_qs': case 'editor_for_qs':
case 'editor_for_as': case 'editor_for_as':
require_once QA_INCLUDE_DIR.'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
$value='-'; // to match none by default, i.e. choose based on who is best at editing HTML $value = '-'; // to match none by default, i.e. choose based on who is best at editing HTML
qa_load_editor('', 'html', $value); qa_load_editor('', 'html', $value);
break; break;
case 'permit_post_q': // convert from deprecated option if available case 'permit_post_q': // convert from deprecated option if available
$value=qa_opt('ask_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL; $value = qa_opt('ask_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL;
break; break;
case 'permit_post_a': // convert from deprecated option if available case 'permit_post_a': // convert from deprecated option if available
$value=qa_opt('answer_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL; $value = qa_opt('answer_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL;
break; break;
case 'permit_post_c': // convert from deprecated option if available case 'permit_post_c': // convert from deprecated option if available
$value=qa_opt('comment_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL; $value = qa_opt('comment_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL;
break; break;
case 'permit_retag_cat': // convert from previous option that used to contain it too case 'permit_retag_cat': // convert from previous option that used to contain it too
$value=qa_opt('permit_edit_q'); $value = qa_opt('permit_edit_q');
break; break;
case 'points_vote_up_q': case 'points_vote_up_q':
case 'points_vote_down_q': case 'points_vote_down_q':
$oldvalue=qa_opt('points_vote_on_q'); $oldvalue = qa_opt('points_vote_on_q');
$value=is_numeric($oldvalue) ? $oldvalue : 1; $value = is_numeric($oldvalue) ? $oldvalue : 1;
break; break;
case 'points_vote_up_a': case 'points_vote_up_a':
case 'points_vote_down_a': case 'points_vote_down_a':
$oldvalue=qa_opt('points_vote_on_a'); $oldvalue = qa_opt('points_vote_on_a');
$value=is_numeric($oldvalue) ? $oldvalue : 1; $value = is_numeric($oldvalue) ? $oldvalue : 1;
break; break;
case 'points_per_q_voted_up': case 'points_per_q_voted_up':
case 'points_per_q_voted_down': case 'points_per_q_voted_down':
$oldvalue=qa_opt('points_per_q_voted'); $oldvalue = qa_opt('points_per_q_voted');
$value=is_numeric($oldvalue) ? $oldvalue : 1; $value = is_numeric($oldvalue) ? $oldvalue : 1;
break; break;
case 'points_per_a_voted_up': case 'points_per_a_voted_up':
case 'points_per_a_voted_down': case 'points_per_a_voted_down':
$oldvalue=qa_opt('points_per_a_voted'); $oldvalue = qa_opt('points_per_a_voted');
$value=is_numeric($oldvalue) ? $oldvalue : 2; $value = is_numeric($oldvalue) ? $oldvalue : 2;
break; break;
case 'captcha_module': case 'captcha_module':
$captchamodules=qa_list_modules('captcha'); $captchamodules = qa_list_modules('captcha');
if (count($captchamodules)) if (count($captchamodules))
$value=reset($captchamodules); $value = reset($captchamodules);
else else
$value=''; $value = '';
break; break;
case 'mailing_from_name': case 'mailing_from_name':
$value=qa_opt('site_title'); $value = qa_opt('site_title');
break; break;
case 'mailing_from_email': case 'mailing_from_email':
$value=qa_opt('from_email'); $value = qa_opt('from_email');
break; break;
case 'mailing_subject': case 'mailing_subject':
$value=qa_lang_sub('options/default_subject', qa_opt('site_title')); $value = qa_lang_sub('options/default_subject', qa_opt('site_title'));
break; break;
case 'mailing_body': case 'mailing_body':
$value="\n\n\n--\n".qa_opt('site_title')."\n".qa_opt('site_url'); $value = "\n\n\n--\n" . qa_opt('site_title') . "\n" . qa_opt('site_url');
break; break;
case 'form_security_salt': case 'form_security_salt':
require_once QA_INCLUDE_DIR.'util/string.php'; require_once QA_INCLUDE_DIR . 'util/string.php';
$value=qa_random_alphanum(32); $value = qa_random_alphanum(32);
break; break;
default: // call option_default method in any registered modules default: // call option_default method in any registered modules
...@@ -503,49 +524,53 @@ ...@@ -503,49 +524,53 @@
return $value; return $value;
} }
$value=''; $value = '';
break; break;
} }
return $value; return $value;
} }
function qa_default_site_title() /**
/* * Return a heuristic guess at the name of the site from the HTTP HOST
Return a heuristic guess at the name of the site from the HTTP HOST */
*/ function qa_default_site_title()
{ {
$parts=explode('.', @$_SERVER['HTTP_HOST']); $parts = explode('.', @$_SERVER['HTTP_HOST']);
$longestpart='';
foreach ($parts as $part)
if (strlen($part)>strlen($longestpart))
$longestpart=$part;
return ((strlen($longestpart)>3) ? (ucfirst($longestpart).' ') : '').qa_lang('options/default_suffix'); $longestpart = '';
foreach ($parts as $part) {
if (strlen($part) > strlen($longestpart))
$longestpart = $part;
} }
return ((strlen($longestpart) > 3) ? (ucfirst($longestpart) . ' ') : '') . qa_lang('options/default_suffix');
}
function qa_post_html_defaults($basetype, $full=false)
/* /**
Return an array of defaults for the $options parameter passed to qa_post_html_fields() and its ilk for posts of $basetype='Q'/'A'/'C' * Return an array of defaults for the $options parameter passed to qa_post_html_fields() and its ilk for posts of $basetype='Q'/'A'/'C'
Set $full to true if these posts will be viewed in full, i.e. on a question page rather than a question listing * Set $full to true if these posts will be viewed in full, i.e. on a question page rather than a question listing
*/ * @param $basetype
{ * @param bool $full
* @return array|mixed
*/
function qa_post_html_defaults($basetype, $full = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'app/users.php'; require_once QA_INCLUDE_DIR . 'app/users.php';
return array( return array(
'tagsview' => ($basetype=='Q') && qa_using_tags(), 'tagsview' => $basetype == 'Q' && qa_using_tags(),
'categoryview' => ($basetype=='Q') && qa_using_categories(), 'categoryview' => $basetype == 'Q' && qa_using_categories(),
'contentview' => $full, 'contentview' => $full,
'voteview' => qa_get_vote_view($basetype, $full), 'voteview' => qa_get_vote_view($basetype, $full),
'flagsview' => qa_opt('flagging_of_posts') && $full, 'flagsview' => qa_opt('flagging_of_posts') && $full,
'favoritedview' => true, 'favoritedview' => true,
'answersview' => $basetype=='Q', 'answersview' => $basetype == 'Q',
'viewsview' => ($basetype=='Q') && qa_opt('do_count_q_views') && ($full ? qa_opt('show_view_count_q_page') : qa_opt('show_view_counts')), 'viewsview' => $basetype == 'Q' && qa_opt('do_count_q_views') && ($full ? qa_opt('show_view_count_q_page') : qa_opt('show_view_counts')),
'whatview' => true, 'whatview' => true,
'whatlink' => qa_opt('show_a_c_links'), 'whatlink' => qa_opt('show_a_c_links'),
'whenview' => qa_opt('show_when_created'), 'whenview' => qa_opt('show_when_created'),
...@@ -561,33 +586,37 @@ ...@@ -561,33 +586,37 @@
'microformats' => $full, 'microformats' => $full,
'fulldatedays' => qa_opt('show_full_date_days'), 'fulldatedays' => qa_opt('show_full_date_days'),
); );
} }
function qa_post_html_options($post, $defaults=null, $full=false) /**
/* * Return an array of options for post $post to pass in the $options parameter to qa_post_html_fields() and its ilk. Preferably,
Return an array of options for post $post to pass in the $options parameter to qa_post_html_fields() and its ilk. Preferably, * call qa_post_html_defaults() previously and pass its output in $defaults, to save excessive recalculation for each item in a
call qa_post_html_defaults() previously and pass its output in $defaults, to save excessive recalculation for each item in a * list. Set $full to true if these posts will be viewed in full, i.e. on a question page rather than a question listing.
list. Set $full to true if these posts will be viewed in full, i.e. on a question page rather than a question listing. * @param $post
*/ * @param $defaults
{ * @param bool $full
* @return array|mixed|null
*/
function qa_post_html_options($post, $defaults = null, $full = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (!isset($defaults)) if (!isset($defaults))
$defaults=qa_post_html_defaults($post['basetype'], $full); $defaults = qa_post_html_defaults($post['basetype'], $full);
$defaults['voteview']=qa_get_vote_view($post, $full); $defaults['voteview'] = qa_get_vote_view($post, $full);
$defaults['ipview']=!qa_user_post_permit_error('permit_anon_view_ips', $post); $defaults['ipview'] = !qa_user_post_permit_error('permit_anon_view_ips', $post);
return $defaults; return $defaults;
} }
function qa_message_html_defaults() /**
/* * Return an array of defaults for the $options parameter passed to qa_message_html_fields()
Return an array of defaults for the $options parameter passed to qa_message_html_fields() */
*/ function qa_message_html_defaults()
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return array( return array(
...@@ -599,138 +628,141 @@ ...@@ -599,138 +628,141 @@
'linksnewwindow' => qa_opt('links_in_new_window'), 'linksnewwindow' => qa_opt('links_in_new_window'),
'fulldatedays' => qa_opt('show_full_date_days'), 'fulldatedays' => qa_opt('show_full_date_days'),
); );
} }
function qa_get_vote_view($postorbasetype, $full=false, $enabledif=true) /**
/* * Return $voteview parameter to pass to qa_post_html_fields() in qa-app-format.php for the post in $postorbasetype
Return $voteview parameter to pass to qa_post_html_fields() in qa-app-format.php for the post in $postorbasetype * with buttons enabled if appropriate (based on whether $full post shown) unless $enabledif is false.
with buttons enabled if appropriate (based on whether $full post shown) unless $enabledif is false. * For compatibility $postorbasetype can also just be a basetype, i.e. 'Q', 'A' or 'C'
For compatibility $postorbasetype can also just be a basetype, i.e. 'Q', 'A' or 'C' * @param $postorbasetype
*/ * @param bool $full
{ * @param bool $enabledif
* @return bool|string
*/
function qa_get_vote_view($postorbasetype, $full = false, $enabledif = true)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// The 'level' and 'approve' permission errors are taken care of by disabling the voting buttons. // The 'level' and 'approve' permission errors are taken care of by disabling the voting buttons.
// Others are reported to the user after they click, in qa_vote_error_html(...) // Others are reported to the user after they click, in qa_vote_error_html(...)
if (is_array($postorbasetype)) { // deal with dual-use parameter if (is_array($postorbasetype)) { // deal with dual-use parameter
$basetype=$postorbasetype['basetype']; $basetype = $postorbasetype['basetype'];
$post=$postorbasetype; $post = $postorbasetype;
} else { } else {
$basetype=$postorbasetype; $basetype = $postorbasetype;
$post=null; $post = null;
} }
$disabledsuffix=''; $disabledsuffix = '';
if (($basetype=='Q') || ($basetype=='A')) { if ($basetype == 'Q' || $basetype == 'A') {
$view=($basetype=='A') ? qa_opt('voting_on_as') : qa_opt('voting_on_qs'); $view = $basetype == 'A' ? qa_opt('voting_on_as') : qa_opt('voting_on_qs');
if (!($enabledif && (($basetype=='A') || $full || !qa_opt('voting_on_q_page_only')))) if (!($enabledif && ($basetype == 'A' || $full || !qa_opt('voting_on_q_page_only'))))
$disabledsuffix='-disabled-page'; $disabledsuffix = '-disabled-page';
else { else {
if ($basetype=='A') if ($basetype == 'A')
$permiterror=isset($post) ? qa_user_post_permit_error('permit_vote_a', $post) : qa_user_permit_error('permit_vote_a'); $permiterror = isset($post) ? qa_user_post_permit_error('permit_vote_a', $post) : qa_user_permit_error('permit_vote_a');
else else
$permiterror=isset($post) ? qa_user_post_permit_error('permit_vote_q', $post) : qa_user_permit_error('permit_vote_q'); $permiterror = isset($post) ? qa_user_post_permit_error('permit_vote_q', $post) : qa_user_permit_error('permit_vote_q');
if ($permiterror=='level')
$disabledsuffix='-disabled-level';
elseif ($permiterror=='approve')
$disabledsuffix='-disabled-approve';
if ($permiterror == 'level')
$disabledsuffix = '-disabled-level';
elseif ($permiterror == 'approve')
$disabledsuffix = '-disabled-approve';
else { else {
$permiterrordown=isset($post) ? qa_user_post_permit_error('permit_vote_down', $post) : qa_user_permit_error('permit_vote_down'); $permiterrordown = isset($post) ? qa_user_post_permit_error('permit_vote_down', $post) : qa_user_permit_error('permit_vote_down');
if ($permiterrordown=='level') if ($permiterrordown == 'level')
$disabledsuffix='-uponly-level'; $disabledsuffix = '-uponly-level';
elseif ($permiterrordown=='approve') elseif ($permiterrordown == 'approve')
$disabledsuffix='-uponly-approve'; $disabledsuffix = '-uponly-approve';
} }
} }
} else } else
$view=false; $view = false;
return $view ? ( (qa_opt('votes_separated') ? 'updown' : 'net').$disabledsuffix ) : false; return $view ? ((qa_opt('votes_separated') ? 'updown' : 'net') . $disabledsuffix) : false;
} }
function qa_has_custom_home() /**
/* * Returns true if the home page has been customized, either due to admin setting, or $QA_CONST_PATH_MAP
Returns true if the home page has been customized, either due to admin setting, or $QA_CONST_PATH_MAP */
*/ function qa_has_custom_home()
{ {
return qa_opt('show_custom_home') || (array_search('', qa_get_request_map())!==false); return qa_opt('show_custom_home') || (array_search('', qa_get_request_map()) !== false);
} }
function qa_using_tags() /**
/* * Return whether the option is set to classify questions by tags
Return whether the option is set to classify questions by tags */
*/ function qa_using_tags()
{ {
return strpos(qa_opt('tags_or_categories'), 't')!==false; return strpos(qa_opt('tags_or_categories'), 't') !== false;
} }
function qa_using_categories() /**
/* * Return whether the option is set to classify questions by categories
Return whether the option is set to classify questions by categories */
*/ function qa_using_categories()
{ {
return strpos(qa_opt('tags_or_categories'), 'c')!==false; return strpos(qa_opt('tags_or_categories'), 'c') !== false;
} }
function qa_get_block_words_preg() /**
/* * Return the regular expression fragment to match the blocked words options set in the database
Return the regular expression fragment to match the blocked words options set in the database */
*/ function qa_get_block_words_preg()
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_blockwordspreg, $qa_blockwordspreg_set; global $qa_blockwordspreg, $qa_blockwordspreg_set;
if (!@$qa_blockwordspreg_set) { if (!@$qa_blockwordspreg_set) {
$blockwordstring=qa_opt('block_bad_words'); $blockwordstring = qa_opt('block_bad_words');
if (strlen($blockwordstring)) { if (strlen($blockwordstring)) {
require_once QA_INCLUDE_DIR.'util/string.php'; require_once QA_INCLUDE_DIR . 'util/string.php';
$qa_blockwordspreg=qa_block_words_to_preg($blockwordstring); $qa_blockwordspreg = qa_block_words_to_preg($blockwordstring);
} else } else
$qa_blockwordspreg=null; $qa_blockwordspreg = null;
$qa_blockwordspreg_set=true; $qa_blockwordspreg_set = true;
} }
return $qa_blockwordspreg; return $qa_blockwordspreg;
} }
function qa_get_points_to_titles() /**
/* * Return an array of [points] => [user title] from the 'points_to_titles' option, to pass to qa_get_points_title_html()
Return an array of [points] => [user title] from the 'points_to_titles' option, to pass to qa_get_points_title_html() */
*/ function qa_get_points_to_titles()
{ {
global $qa_points_title_cache; global $qa_points_title_cache;
if (!is_array($qa_points_title_cache)) { if (!is_array($qa_points_title_cache)) {
$qa_points_title_cache=array(); $qa_points_title_cache = array();
$pairs=explode(',', qa_opt('points_to_titles')); $pairs = explode(',', qa_opt('points_to_titles'));
foreach ($pairs as $pair) { foreach ($pairs as $pair) {
$spacepos=strpos($pair, ' '); $spacepos = strpos($pair, ' ');
if (is_numeric($spacepos)) { if (is_numeric($spacepos)) {
$points=trim(substr($pair, 0, $spacepos)); $points = trim(substr($pair, 0, $spacepos));
$title=trim(substr($pair, $spacepos)); $title = trim(substr($pair, $spacepos));
if (is_numeric($points) && strlen($title)) if (is_numeric($points) && strlen($title))
$qa_points_title_cache[(int)$points]=$title; $qa_points_title_cache[(int)$points] = $title;
} }
} }
...@@ -738,64 +770,59 @@ ...@@ -738,64 +770,59 @@
} }
return $qa_points_title_cache; return $qa_points_title_cache;
} }
function qa_get_permit_options() /**
/* * Return an array of relevant permissions settings, based on other options
Return an array of relevant permissions settings, based on other options */
*/ function qa_get_permit_options()
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$permits=array('permit_view_q_page', 'permit_post_q', 'permit_post_a'); $permits = array('permit_view_q_page', 'permit_post_q', 'permit_post_a');
if (qa_opt('comment_on_qs') || qa_opt('comment_on_as')) if (qa_opt('comment_on_qs') || qa_opt('comment_on_as'))
$permits[]='permit_post_c'; $permits[] = 'permit_post_c';
if (qa_opt('voting_on_qs')) if (qa_opt('voting_on_qs'))
$permits[]='permit_vote_q'; $permits[] = 'permit_vote_q';
if (qa_opt('voting_on_as')) if (qa_opt('voting_on_as'))
$permits[]='permit_vote_a'; $permits[] = 'permit_vote_a';
if (qa_opt('voting_on_qs') || qa_opt('voting_on_as')) if (qa_opt('voting_on_qs') || qa_opt('voting_on_as'))
$permits[]='permit_vote_down'; $permits[] = 'permit_vote_down';
if (qa_using_tags() || qa_using_categories()) if (qa_using_tags() || qa_using_categories())
$permits[]='permit_retag_cat'; $permits[] = 'permit_retag_cat';
array_push($permits, 'permit_edit_q', 'permit_edit_a'); array_push($permits, 'permit_edit_q', 'permit_edit_a');
if (qa_opt('comment_on_qs') || qa_opt('comment_on_as')) if (qa_opt('comment_on_qs') || qa_opt('comment_on_as'))
$permits[]='permit_edit_c'; $permits[] = 'permit_edit_c';
$permits[]='permit_edit_silent'; $permits[] = 'permit_edit_silent';
if (qa_opt('allow_close_questions')) if (qa_opt('allow_close_questions'))
$permits[]='permit_close_q'; $permits[] = 'permit_close_q';
array_push($permits, 'permit_select_a', 'permit_anon_view_ips'); array_push($permits, 'permit_select_a', 'permit_anon_view_ips');
if (qa_opt('voting_on_qs') || qa_opt('voting_on_as') || qa_opt('flagging_of_posts')) if (qa_opt('voting_on_qs') || qa_opt('voting_on_as') || qa_opt('flagging_of_posts'))
$permits[]='permit_view_voters_flaggers'; $permits[] = 'permit_view_voters_flaggers';
if (qa_opt('flagging_of_posts')) if (qa_opt('flagging_of_posts'))
$permits[]='permit_flag'; $permits[] = 'permit_flag';
$permits[]='permit_moderate'; $permits[] = 'permit_moderate';
array_push($permits, 'permit_hide_show', 'permit_delete_hidden'); array_push($permits, 'permit_hide_show', 'permit_delete_hidden');
if (qa_opt('allow_user_walls')) if (qa_opt('allow_user_walls'))
$permits[]='permit_post_wall'; $permits[] = 'permit_post_wall';
array_push($permits, 'permit_view_new_users_page', 'permit_view_special_users_page'); array_push($permits, 'permit_view_new_users_page', 'permit_view_special_users_page');
return $permits; return $permits;
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
...@@ -20,173 +20,208 @@ ...@@ -20,173 +20,208 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
require_once QA_INCLUDE_DIR.'qa-db.php'; require_once QA_INCLUDE_DIR . 'qa-db.php';
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR.'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR.'app/post-create.php'; require_once QA_INCLUDE_DIR . 'app/post-create.php';
require_once QA_INCLUDE_DIR.'app/post-update.php'; require_once QA_INCLUDE_DIR . 'app/post-update.php';
require_once QA_INCLUDE_DIR.'app/users.php'; require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR.'util/string.php'; require_once QA_INCLUDE_DIR . 'util/string.php';
function qa_post_create($type, $parentid, $title, $content, $format='', $categoryid=null, $tags=null, $userid=null, $notify=null, $email=null, $extravalue=null, $name=null) /**
/* * Create a new post in the database, and return its postid.
Create a new post in the database, and return its postid. *
* Set $type to 'Q' for a new question, 'A' for an answer, or 'C' for a comment. You can also use 'Q_QUEUED',
Set $type to 'Q' for a new question, 'A' for an answer, or 'C' for a comment. You can also use 'Q_QUEUED', * 'A_QUEUED' or 'C_QUEUED' to create a post which is queued for moderator approval. For questions, set $parentid to
'A_QUEUED' or 'C_QUEUED' to create a post which is queued for moderator approval. For questions, set $parentid to * the postid of the answer to which the question is related, or null if (as in most cases) the question is not related
the postid of the answer to which the question is related, or null if (as in most cases) the question is not related * to an answer. For answers, set $parentid to the postid of the question being answered. For comments, set $parentid
to an answer. For answers, set $parentid to the postid of the question being answered. For comments, set $parentid * to the postid of the question or answer to which the comment relates. The $content and $format parameters go
to the postid of the question or answer to which the comment relates. The $content and $format parameters go * together - if $format is '' then $content should be in plain UTF-8 text, and if $format is 'html' then $content
together - if $format is '' then $content should be in plain UTF-8 text, and if $format is 'html' then $content * should be in UTF-8 HTML. Other values of $format may be allowed if an appropriate viewer module is installed. The
should be in UTF-8 HTML. Other values of $format may be allowed if an appropriate viewer module is installed. The * $title, $categoryid and $tags parameters are only relevant when creating a question - $tags can either be an array
$title, $categoryid and $tags parameters are only relevant when creating a question - $tags can either be an array * of tags, or a string of tags separated by commas. The new post will be assigned to $userid if it is not null,
of tags, or a string of tags separated by commas. The new post will be assigned to $userid if it is not null, * otherwise it will be by a non-user. If $notify is true then the author will be sent notifications relating to the
otherwise it will be by a non-user. If $notify is true then the author will be sent notifications relating to the * post - either to $email if it is specified and valid, or to the current email address of $userid if $email is '@'.
post - either to $email if it is specified and valid, or to the current email address of $userid if $email is '@'. * If you're creating a question, the $extravalue parameter will be set as the custom extra field, if not null. For all
If you're creating a question, the $extravalue parameter will be set as the custom extra field, if not null. For all * post types you can specify the $name of the post's author, which is relevant if the $userid is null.
post types you can specify the $name of the post's author, which is relevant if the $userid is null. * @param $type
*/ * @param $parentid
{ * @param $title
$handle=qa_userid_to_handle($userid); * @param $content
$text=qa_post_content_to_text($content, $format); * @param string $format
* @param $categoryid
* @param $tags
* @param $userid
* @param $notify
* @param $email
* @param $extravalue
* @param $name
* @return mixed
*/
function qa_post_create($type, $parentid, $title, $content, $format = '', $categoryid = null, $tags = null, $userid = null,
$notify = null, $email = null, $extravalue = null, $name = null)
{
$handle = qa_userid_to_handle($userid);
$text = qa_post_content_to_text($content, $format);
switch ($type) { switch ($type) {
case 'Q': case 'Q':
case 'Q_QUEUED': case 'Q_QUEUED':
$followanswer=isset($parentid) ? qa_post_get_full($parentid, 'A') : null; $followanswer = isset($parentid) ? qa_post_get_full($parentid, 'A') : null;
$tagstring=qa_post_tags_to_tagstring($tags); $tagstring = qa_post_tags_to_tagstring($tags);
$postid=qa_question_create($followanswer, $userid, $handle, null, $title, $content, $format, $text, $tagstring, $postid = qa_question_create($followanswer, $userid, $handle, null, $title, $content, $format, $text, $tagstring,
$notify, $email, $categoryid, $extravalue, $type=='Q_QUEUED', $name); $notify, $email, $categoryid, $extravalue, $type == 'Q_QUEUED', $name);
break; break;
case 'A': case 'A':
case 'A_QUEUED': case 'A_QUEUED':
$question=qa_post_get_full($parentid, 'Q'); $question = qa_post_get_full($parentid, 'Q');
$postid=qa_answer_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $type=='A_QUEUED', $name); $postid = qa_answer_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $type == 'A_QUEUED', $name);
break; break;
case 'C': case 'C':
case 'C_QUEUED': case 'C_QUEUED':
$parent=qa_post_get_full($parentid, 'QA'); $parent = qa_post_get_full($parentid, 'QA');
$commentsfollows=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $parentid)); $commentsfollows = qa_db_single_select(qa_db_full_child_posts_selectspec(null, $parentid));
$question=qa_post_parent_to_question($parent); $question = qa_post_parent_to_question($parent);
$postid=qa_comment_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $parent, $commentsfollows, $type=='C_QUEUED', $name); $postid = qa_comment_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $parent, $commentsfollows, $type == 'C_QUEUED', $name);
break; break;
default: default:
qa_fatal_error('Post type not recognized: '.$type); qa_fatal_error('Post type not recognized: ' . $type);
break; break;
} }
return $postid; return $postid;
} }
function qa_post_set_content($postid, $title, $content, $format=null, $tags=null, $notify=null, $email=null, $byuserid=null, $extravalue=null, $name=null) /**
/* * Change the data stored for post $postid based on any of the $title, $content, $format, $tags, $notify, $email,
Change the data stored for post $postid based on any of the $title, $content, $format, $tags, $notify, $email, * $extravalue and $name parameters passed which are not null. The meaning of these parameters is the same as for
$extravalue and $name parameters passed which are not null. The meaning of these parameters is the same as for * qa_post_create() above. Pass the identify of the user making this change in $byuserid (or null for silent).
qa_post_create() above. Pass the identify of the user making this change in $byuserid (or null for silent). * @param $postid
*/ * @param $title
{ * @param $content
$oldpost=qa_post_get_full($postid, 'QAC'); * @param $format
* @param $tags
* @param $notify
* @param $email
* @param $byuserid
* @param $extravalue
* @param $name
*/
function qa_post_set_content($postid, $title, $content, $format = null, $tags = null, $notify = null, $email = null, $byuserid = null, $extravalue = null, $name = null)
{
$oldpost = qa_post_get_full($postid, 'QAC');
if (!isset($title)) if (!isset($title))
$title=$oldpost['title']; $title = $oldpost['title'];
if (!isset($content)) if (!isset($content))
$content=$oldpost['content']; $content = $oldpost['content'];
if (!isset($format)) if (!isset($format))
$format=$oldpost['format']; $format = $oldpost['format'];
if (!isset($tags)) if (!isset($tags))
$tags=qa_tagstring_to_tags($oldpost['tags']); $tags = qa_tagstring_to_tags($oldpost['tags']);
if (isset($notify) || isset($email)) if (isset($notify) || isset($email))
$setnotify=qa_combine_notify_email($oldpost['userid'], isset($notify) ? $notify : isset($oldpost['notify']), $setnotify = qa_combine_notify_email($oldpost['userid'], isset($notify) ? $notify : isset($oldpost['notify']),
isset($email) ? $email : $oldpost['notify']); isset($email) ? $email : $oldpost['notify']);
else else
$setnotify=$oldpost['notify']; $setnotify = $oldpost['notify'];
$byhandle=qa_userid_to_handle($byuserid); $byhandle = qa_userid_to_handle($byuserid);
$text=qa_post_content_to_text($content, $format); $text = qa_post_content_to_text($content, $format);
switch ($oldpost['basetype']) { switch ($oldpost['basetype']) {
case 'Q': case 'Q':
$tagstring=qa_post_tags_to_tagstring($tags); $tagstring = qa_post_tags_to_tagstring($tags);
qa_question_set_content($oldpost, $title, $content, $format, $text, $tagstring, $setnotify, $byuserid, $byhandle, null, $extravalue, $name); qa_question_set_content($oldpost, $title, $content, $format, $text, $tagstring, $setnotify, $byuserid, $byhandle, null, $extravalue, $name);
break; break;
case 'A': case 'A':
$question=qa_post_get_full($oldpost['parentid'], 'Q'); $question = qa_post_get_full($oldpost['parentid'], 'Q');
qa_answer_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $name); qa_answer_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $name);
break; break;
case 'C': case 'C':
$parent=qa_post_get_full($oldpost['parentid'], 'QA'); $parent = qa_post_get_full($oldpost['parentid'], 'QA');
$question=qa_post_parent_to_question($parent); $question = qa_post_parent_to_question($parent);
qa_comment_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $parent, $name); qa_comment_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $parent, $name);
break; break;
} }
} }
function qa_post_set_category($postid, $categoryid, $byuserid=null) /**
/* * Change the category of $postid to $categoryid. The category of all related posts (shown together on the same
Change the category of $postid to $categoryid. The category of all related posts (shown together on the same * question page) will also be changed. Pass the identify of the user making this change in $byuserid (or null for an
question page) will also be changed. Pass the identify of the user making this change in $byuserid (or null for an * anonymous change).
anonymous change). * @param $postid
*/ * @param $categoryid
{ * @param $byuserid
$oldpost=qa_post_get_full($postid, 'QAC'); */
function qa_post_set_category($postid, $categoryid, $byuserid = null)
if ($oldpost['basetype']=='Q') { {
$byhandle=qa_userid_to_handle($byuserid); $oldpost = qa_post_get_full($postid, 'QAC');
$answers=qa_post_get_question_answers($postid);
$commentsfollows=qa_post_get_question_commentsfollows($postid); if ($oldpost['basetype'] == 'Q') {
$closepost=qa_post_get_question_closepost($postid); $byhandle = qa_userid_to_handle($byuserid);
$answers = qa_post_get_question_answers($postid);
$commentsfollows = qa_post_get_question_commentsfollows($postid);
$closepost = qa_post_get_question_closepost($postid);
qa_question_set_category($oldpost, $categoryid, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost); qa_question_set_category($oldpost, $categoryid, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost);
} else } else
qa_post_set_category($oldpost['parentid'], $categoryid, $byuserid); // keep looking until we find the parent question qa_post_set_category($oldpost['parentid'], $categoryid, $byuserid); // keep looking until we find the parent question
} }
function qa_post_set_selchildid($questionid, $answerid, $byuserid=null) /**
/* * Set the selected best answer of $questionid to $answerid (or to none if $answerid is null). Pass the identify of the
Set the selected best answer of $questionid to $answerid (or to none if $answerid is null). Pass the identify of the * user in $byuserid (or null for an anonymous change).
user in $byuserid (or null for an anonymous change). * @param $questionid
*/ * @param $answerid
{ * @param $byuserid
$oldquestion=qa_post_get_full($questionid, 'Q'); */
$byhandle=qa_userid_to_handle($byuserid); function qa_post_set_selchildid($questionid, $answerid, $byuserid = null)
$answers=qa_post_get_question_answers($questionid); {
$oldquestion = qa_post_get_full($questionid, 'Q');
$byhandle = qa_userid_to_handle($byuserid);
$answers = qa_post_get_question_answers($questionid);
if (isset($answerid) && !isset($answers[$answerid])) if (isset($answerid) && !isset($answers[$answerid]))
qa_fatal_error('Answer ID could not be found: '.$answerid); qa_fatal_error('Answer ID could not be found: ' . $answerid);
qa_question_set_selchildid($byuserid, $byhandle, null, $oldquestion, $answerid, $answers); qa_question_set_selchildid($byuserid, $byhandle, null, $oldquestion, $answerid, $answers);
} }
function qa_post_set_closed($questionid, $closed=true, $originalpostid=null, $note=null, $byuserid=null) /**
/* * Closed $questionid if $closed is true, otherwise reopen it. If $closed is true, pass either the $originalpostid of
Closed $questionid if $closed is true, otherwise reopen it. If $closed is true, pass either the $originalpostid of * the question that it is a duplicate of, or a $note to explain why it's closed. Pass the identify of the user in
the question that it is a duplicate of, or a $note to explain why it's closed. Pass the identify of the user in * $byuserid (or null for an anonymous change).
$byuserid (or null for an anonymous change). * @param $questionid
*/ * @param bool $closed
{ * @param $originalpostid
$oldquestion=qa_post_get_full($questionid, 'Q'); * @param $note
$oldclosepost=qa_post_get_question_closepost($questionid); * @param $byuserid
$byhandle=qa_userid_to_handle($byuserid); */
function qa_post_set_closed($questionid, $closed = true, $originalpostid = null, $note = null, $byuserid = null)
{
$oldquestion = qa_post_get_full($questionid, 'Q');
$oldclosepost = qa_post_get_question_closepost($questionid);
$byhandle = qa_userid_to_handle($byuserid);
if ($closed) { if ($closed) {
if (isset($originalpostid)) if (isset($originalpostid))
...@@ -198,57 +233,65 @@ ...@@ -198,57 +233,65 @@
} else } else
qa_question_close_clear($oldquestion, $oldclosepost, $byuserid, $byhandle, null); qa_question_close_clear($oldquestion, $oldclosepost, $byuserid, $byhandle, null);
} }
function qa_post_set_hidden($postid, $hidden=true, $byuserid=null) /**
/* * Hide $postid if $hidden is true, otherwise show the post. Pass the identify of the user making this change in
Hide $postid if $hidden is true, otherwise show the post. Pass the identify of the user making this change in * $byuserid (or null for a silent change). This function is included mainly for backwards compatibility.
$byuserid (or null for a silent change). This function is included mainly for backwards compatibility. * @param $postid
*/ * @param bool $hidden
{ * @param $byuserid
*/
function qa_post_set_hidden($postid, $hidden = true, $byuserid = null)
{
qa_post_set_status($postid, $hidden ? QA_POST_STATUS_HIDDEN : QA_POST_STATUS_NORMAL, $byuserid); qa_post_set_status($postid, $hidden ? QA_POST_STATUS_HIDDEN : QA_POST_STATUS_NORMAL, $byuserid);
} }
function qa_post_set_status($postid, $status, $byuserid=null) /**
/* * Change the status of $postid to $status, which should be one of the QA_POST_STATUS_* constants defined in
Change the status of $postid to $status, which should be one of the QA_POST_STATUS_* constants defined in * qa-app-post-update.php. Pass the identify of the user making this change in $byuserid (or null for a silent change).
qa-app-post-update.php. Pass the identify of the user making this change in $byuserid (or null for a silent change). * @param $postid
*/ * @param $status
{ * @param $byuserid
$oldpost=qa_post_get_full($postid, 'QAC'); */
$byhandle=qa_userid_to_handle($byuserid); function qa_post_set_status($postid, $status, $byuserid = null)
{
$oldpost = qa_post_get_full($postid, 'QAC');
$byhandle = qa_userid_to_handle($byuserid);
switch ($oldpost['basetype']) { switch ($oldpost['basetype']) {
case 'Q': case 'Q':
$answers=qa_post_get_question_answers($postid); $answers = qa_post_get_question_answers($postid);
$commentsfollows=qa_post_get_question_commentsfollows($postid); $commentsfollows = qa_post_get_question_commentsfollows($postid);
$closepost=qa_post_get_question_closepost($postid); $closepost = qa_post_get_question_closepost($postid);
qa_question_set_status($oldpost, $status, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost); qa_question_set_status($oldpost, $status, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost);
break; break;
case 'A': case 'A':
$question=qa_post_get_full($oldpost['parentid'], 'Q'); $question = qa_post_get_full($oldpost['parentid'], 'Q');
$commentsfollows=qa_post_get_answer_commentsfollows($postid); $commentsfollows = qa_post_get_answer_commentsfollows($postid);
qa_answer_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $commentsfollows); qa_answer_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $commentsfollows);
break; break;
case 'C': case 'C':
$parent=qa_post_get_full($oldpost['parentid'], 'QA'); $parent = qa_post_get_full($oldpost['parentid'], 'QA');
$question=qa_post_parent_to_question($parent); $question = qa_post_parent_to_question($parent);
qa_comment_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $parent); qa_comment_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $parent);
break; break;
} }
} }
function qa_post_set_created($postid, $created) /**
/* * Set the created date of $postid to $created, which is a unix timestamp.
Set the created date of $postid to $created, which is a unix timestamp. * @param $postid
*/ * @param $created
{ */
$oldpost=qa_post_get_full($postid); function qa_post_set_created($postid, $created)
{
$oldpost = qa_post_get_full($postid);
qa_db_post_set_created($postid, $created); qa_db_post_set_created($postid, $created);
...@@ -261,187 +304,207 @@ ...@@ -261,187 +304,207 @@
qa_db_hotness_update($oldpost['parentid']); qa_db_hotness_update($oldpost['parentid']);
break; break;
} }
} }
function qa_post_delete($postid) /**
/* * Delete $postid from the database, hiding it first if appropriate.
Delete $postid from the database, hiding it first if appropriate. * @param $postid
*/ */
{ function qa_post_delete($postid)
$oldpost=qa_post_get_full($postid, 'QAC'); {
$oldpost = qa_post_get_full($postid, 'QAC');
if (!$oldpost['hidden']) { if (!$oldpost['hidden']) {
qa_post_set_hidden($postid, true, null); qa_post_set_hidden($postid, true, null);
$oldpost=qa_post_get_full($postid, 'QAC'); $oldpost = qa_post_get_full($postid, 'QAC');
} }
switch ($oldpost['basetype']) { switch ($oldpost['basetype']) {
case 'Q': case 'Q':
$answers=qa_post_get_question_answers($postid); $answers = qa_post_get_question_answers($postid);
$commentsfollows=qa_post_get_question_commentsfollows($postid); $commentsfollows = qa_post_get_question_commentsfollows($postid);
$closepost=qa_post_get_question_closepost($postid); $closepost = qa_post_get_question_closepost($postid);
if (count($answers) || count($commentsfollows)) if (count($answers) || count($commentsfollows))
qa_fatal_error('Could not delete question ID due to dependents: '.$postid); qa_fatal_error('Could not delete question ID due to dependents: ' . $postid);
qa_question_delete($oldpost, null, null, null, $closepost); qa_question_delete($oldpost, null, null, null, $closepost);
break; break;
case 'A': case 'A':
$question=qa_post_get_full($oldpost['parentid'], 'Q'); $question = qa_post_get_full($oldpost['parentid'], 'Q');
$commentsfollows=qa_post_get_answer_commentsfollows($postid); $commentsfollows = qa_post_get_answer_commentsfollows($postid);
if (count($commentsfollows)) if (count($commentsfollows))
qa_fatal_error('Could not delete answer ID due to dependents: '.$postid); qa_fatal_error('Could not delete answer ID due to dependents: ' . $postid);
qa_answer_delete($oldpost, $question, null, null, null); qa_answer_delete($oldpost, $question, null, null, null);
break; break;
case 'C': case 'C':
$parent=qa_post_get_full($oldpost['parentid'], 'QA'); $parent = qa_post_get_full($oldpost['parentid'], 'QA');
$question=qa_post_parent_to_question($parent); $question = qa_post_parent_to_question($parent);
qa_comment_delete($oldpost, $question, $parent, null, null, null); qa_comment_delete($oldpost, $question, $parent, null, null, null);
break; break;
} }
} }
function qa_post_get_full($postid, $requiredbasetypes=null) /**
/* * Return the full information from the database for $postid in an array.
Return the full information from the database for $postid in an array. * @param $postid
*/ * @param $requiredbasetypes
{ * @return array|mixed
$post=qa_db_single_select(qa_db_full_post_selectspec(null, $postid)); */
function qa_post_get_full($postid, $requiredbasetypes = null)
{
$post = qa_db_single_select(qa_db_full_post_selectspec(null, $postid));
if (!is_array($post)) if (!is_array($post))
qa_fatal_error('Post ID could not be found: '.$postid); qa_fatal_error('Post ID could not be found: ' . $postid);
if (isset($requiredbasetypes) && !is_numeric(strpos($requiredbasetypes, $post['basetype']))) if (isset($requiredbasetypes) && !is_numeric(strpos($requiredbasetypes, $post['basetype'])))
qa_fatal_error('Post of wrong type: '.$post['basetype']); qa_fatal_error('Post of wrong type: ' . $post['basetype']);
return $post; return $post;
} }
/** /**
* Return the handle corresponding to $userid, unless it is null in which case return null. * Return the handle corresponding to $userid, unless it is null in which case return null.
* *
* @deprecated Deprecated from 1.7; use `qa_userid_to_handle($userid)` instead. * @deprecated Deprecated from 1.7; use `qa_userid_to_handle($userid)` instead.
* @param $userid
* @return mixed|null
*/ */
function qa_post_userid_to_handle($userid) function qa_post_userid_to_handle($userid)
{ {
return qa_userid_to_handle($userid); return qa_userid_to_handle($userid);
} }
function qa_post_content_to_text($content, $format) /**
/* * Return the textual rendition of $content in $format (used for indexing).
Return the textual rendition of $content in $format (used for indexing). * @param $content
*/ * @param $format
{ * @return
$viewer=qa_load_viewer($content, $format); */
function qa_post_content_to_text($content, $format)
{
$viewer = qa_load_viewer($content, $format);
if (!isset($viewer)) if (!isset($viewer))
qa_fatal_error('Content could not be parsed in format: '.$format); qa_fatal_error('Content could not be parsed in format: ' . $format);
return $viewer->get_text($content, $format, array()); return $viewer->get_text($content, $format, array());
} }
function qa_post_tags_to_tagstring($tags) /**
/* * Return tagstring to store in the database based on $tags as an array or a comma-separated string.
Return tagstring to store in the database based on $tags as an array or a comma-separated string. * @param $tags
*/ * @return mixed|string
{ */
function qa_post_tags_to_tagstring($tags)
{
if (is_array($tags)) if (is_array($tags))
$tags=implode(',', $tags); $tags = implode(',', $tags);
return qa_tags_to_tagstring(array_unique(preg_split('/\s*,\s*/', qa_strtolower(strtr($tags, '/', ' ')), -1, PREG_SPLIT_NO_EMPTY))); return qa_tags_to_tagstring(array_unique(preg_split('/\s*,\s*/', qa_strtolower(strtr($tags, '/', ' ')), -1, PREG_SPLIT_NO_EMPTY)));
} }
function qa_post_get_question_answers($questionid) /**
/* * Return the full database records for all answers to question $questionid
Return the full database records for all answers to question $questionid * @param $questionid
*/ * @return array
{ */
$answers=array(); function qa_post_get_question_answers($questionid)
{
$answers = array();
$childposts=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $questionid)); $childposts = qa_db_single_select(qa_db_full_child_posts_selectspec(null, $questionid));
foreach ($childposts as $postid => $post) foreach ($childposts as $postid => $post) {
if ($post['basetype']=='A') if ($post['basetype'] == 'A')
$answers[$postid]=$post; $answers[$postid] = $post;
}
return $answers; return $answers;
} }
function qa_post_get_question_commentsfollows($questionid) /**
/* * Return the full database records for all comments or follow-on questions for question $questionid or its answers
Return the full database records for all comments or follow-on questions for question $questionid or its answers * @param $questionid
*/ * @return array
{ */
$commentsfollows=array(); function qa_post_get_question_commentsfollows($questionid)
{
$commentsfollows = array();
list($childposts, $achildposts)=qa_db_multi_select(array( list($childposts, $achildposts) = qa_db_multi_select(array(
qa_db_full_child_posts_selectspec(null, $questionid), qa_db_full_child_posts_selectspec(null, $questionid),
qa_db_full_a_child_posts_selectspec(null, $questionid), qa_db_full_a_child_posts_selectspec(null, $questionid),
)); ));
foreach ($childposts as $postid => $post) foreach ($childposts as $postid => $post) {
if ($post['basetype']=='C') if ($post['basetype'] == 'C')
$commentsfollows[$postid]=$post; $commentsfollows[$postid] = $post;
}
foreach ($achildposts as $postid => $post) foreach ($achildposts as $postid => $post) {
if ( ($post['basetype']=='Q') || ($post['basetype']=='C') ) if (($post['basetype'] == 'Q') || ($post['basetype'] == 'C'))
$commentsfollows[$postid]=$post; $commentsfollows[$postid] = $post;
}
return $commentsfollows; return $commentsfollows;
} }
function qa_post_get_question_closepost($questionid) /**
/* * Return the full database record for the post which closed $questionid, if there is any
Return the full database record for the post which closed $questionid, if there is any * @param $questionid
*/ * @return array|mixed
{ */
function qa_post_get_question_closepost($questionid)
{
return qa_db_single_select(qa_db_post_close_post_selectspec($questionid)); return qa_db_single_select(qa_db_post_close_post_selectspec($questionid));
} }
function qa_post_get_answer_commentsfollows($answerid) /**
/* * Return the full database records for all comments or follow-on questions for answer $answerid
Return the full database records for all comments or follow-on questions for answer $answerid * @param $answerid
*/ * @return array
{ */
$commentsfollows=array(); function qa_post_get_answer_commentsfollows($answerid)
{
$commentsfollows = array();
$childposts=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $answerid)); $childposts = qa_db_single_select(qa_db_full_child_posts_selectspec(null, $answerid));
foreach ($childposts as $postid => $post) foreach ($childposts as $postid => $post) {
if ( ($post['basetype']=='Q') || ($post['basetype']=='C') ) if (($post['basetype'] == 'Q') || ($post['basetype'] == 'C'))
$commentsfollows[$postid]=$post; $commentsfollows[$postid] = $post;
}
return $commentsfollows; return $commentsfollows;
} }
function qa_post_parent_to_question($parent) /**
/* * Return $parent if it's the database record for a question, otherwise return the database record for its parent
Return $parent if it's the database record for a question, otherwise return the database record for its parent * @param $parent
*/ * @return array|mixed
{ */
if ($parent['basetype']=='Q') function qa_post_parent_to_question($parent)
$question=$parent; {
if ($parent['basetype'] == 'Q')
$question = $parent;
else else
$question=qa_post_get_full($parent['parentid'], 'Q'); $question = qa_post_get_full($parent['parentid'], 'Q');
return $question; return $question;
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,51 +20,67 @@ ...@@ -20,51 +20,67 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
function qa_q_list_page_content($questions, $pagesize, $start, $count, $sometitle, $nonetitle, /**
* Returns the $qa_content structure for a question list page showing $questions retrieved from the
* database. If $pagesize is not null, it sets the max number of questions to display. If $count is
* not null, pagination is determined by $start and $count. The page title is $sometitle unless
* there are no questions shown, in which case it's $nonetitle. $navcategories should contain the
* categories retrived from the database using qa_db_category_nav_selectspec(...) for $categoryid,
* which is the current category shown. If $categorypathprefix is set, category navigation will be
* shown, with per-category question counts if $categoryqcount is true. The nav links will have the
* prefix $categorypathprefix and possible extra $categoryparams. If $feedpathprefix is set, the
* page has an RSS feed whose URL uses that prefix. If there are no links to other pages, $suggest
* is used to suggest what the user should do. The $pagelinkparams are passed through to
* qa_html_page_links(...) which creates links for page 2, 3, etc..
* @param $questions
* @param $pagesize
* @param $start
* @param $count
* @param $sometitle
* @param $nonetitle
* @param $navcategories
* @param $categoryid
* @param $categoryqcount
* @param $categorypathprefix
* @param $feedpathprefix
* @param $suggest
* @param $pagelinkparams
* @param $categoryparams
* @param $dummy
* @return array
*/
function qa_q_list_page_content($questions, $pagesize, $start, $count, $sometitle, $nonetitle,
$navcategories, $categoryid, $categoryqcount, $categorypathprefix, $feedpathprefix, $suggest, $navcategories, $categoryid, $categoryqcount, $categorypathprefix, $feedpathprefix, $suggest,
$pagelinkparams=null, $categoryparams=null, $dummy=null) $pagelinkparams = null, $categoryparams = null, $dummy = null)
/* {
Returns the $qa_content structure for a question list page showing $questions retrieved from the
database. If $pagesize is not null, it sets the max number of questions to display. If $count is
not null, pagination is determined by $start and $count. The page title is $sometitle unless
there are no questions shown, in which case it's $nonetitle. $navcategories should contain the
categories retrived from the database using qa_db_category_nav_selectspec(...) for $categoryid,
which is the current category shown. If $categorypathprefix is set, category navigation will be
shown, with per-category question counts if $categoryqcount is true. The nav links will have the
prefix $categorypathprefix and possible extra $categoryparams. If $feedpathprefix is set, the
page has an RSS feed whose URL uses that prefix. If there are no links to other pages, $suggest
is used to suggest what the user should do. The $pagelinkparams are passed through to
qa_html_page_links(...) which creates links for page 2, 3, etc..
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR.'app/updates.php'; require_once QA_INCLUDE_DIR . 'app/updates.php';
$userid=qa_get_logged_in_userid(); $userid = qa_get_logged_in_userid();
// Chop down to size, get user information for display // Chop down to size, get user information for display
if (isset($pagesize)) if (isset($pagesize))
$questions=array_slice($questions, 0, $pagesize); $questions = array_slice($questions, 0, $pagesize);
$usershtml=qa_userids_handles_html(qa_any_get_userids_handles($questions)); $usershtml = qa_userids_handles_html(qa_any_get_userids_handles($questions));
// Prepare content for theme // Prepare content for theme
$qa_content=qa_content_prepare(true, array_keys(qa_category_path($navcategories, $categoryid))); $qa_content = qa_content_prepare(true, array_keys(qa_category_path($navcategories, $categoryid)));
$qa_content['q_list']['form']=array( $qa_content['q_list']['form'] = array(
'tags' => 'method="post" action="'.qa_self_html().'"', 'tags' => 'method="post" action="' . qa_self_html() . '"',
'hidden' => array( 'hidden' => array(
'code' => qa_get_form_security_code('vote'), 'code' => qa_get_form_security_code('vote'),
...@@ -92,49 +108,53 @@ ...@@ -92,49 +108,53 @@
$qa_content['q_list']['qs'][] = $fields; $qa_content['q_list']['qs'][] = $fields;
} }
} } else
else
$qa_content['title'] = $nonetitle; $qa_content['title'] = $nonetitle;
if (isset($userid) && isset($categoryid)) { if (isset($userid) && isset($categoryid)) {
$favoritemap=qa_get_favorite_non_qs_map(); $favoritemap = qa_get_favorite_non_qs_map();
$categoryisfavorite = @$favoritemap['category'][$navcategories[$categoryid]['backpath']]; $categoryisfavorite = @$favoritemap['category'][$navcategories[$categoryid]['backpath']];
$qa_content['favorite']=qa_favorite_form(QA_ENTITY_CATEGORY, $categoryid, $categoryisfavorite, $qa_content['favorite'] = qa_favorite_form(QA_ENTITY_CATEGORY, $categoryid, $categoryisfavorite,
qa_lang_sub($categoryisfavorite ? 'main/remove_x_favorites' : 'main/add_category_x_favorites', $navcategories[$categoryid]['title'])); qa_lang_sub($categoryisfavorite ? 'main/remove_x_favorites' : 'main/add_category_x_favorites', $navcategories[$categoryid]['title']));
} }
if (isset($count) && isset($pagesize)) if (isset($count) && isset($pagesize))
$qa_content['page_links']=qa_html_page_links(qa_request(), $start, $pagesize, $count, qa_opt('pages_prev_next'), $pagelinkparams); $qa_content['page_links'] = qa_html_page_links(qa_request(), $start, $pagesize, $count, qa_opt('pages_prev_next'), $pagelinkparams);
if (empty($qa_content['page_links'])) if (empty($qa_content['page_links']))
$qa_content['suggest_next']=$suggest; $qa_content['suggest_next'] = $suggest;
if (qa_using_categories() && count($navcategories) && isset($categorypathprefix)) if (qa_using_categories() && count($navcategories) && isset($categorypathprefix))
$qa_content['navigation']['cat']=qa_category_navigation($navcategories, $categoryid, $categorypathprefix, $categoryqcount, $categoryparams); $qa_content['navigation']['cat'] = qa_category_navigation($navcategories, $categoryid, $categorypathprefix, $categoryqcount, $categoryparams);
if (isset($feedpathprefix) && (qa_opt('feed_per_category') || !isset($categoryid)) ) if (isset($feedpathprefix) && (qa_opt('feed_per_category') || !isset($categoryid)))
$qa_content['feed']=array( $qa_content['feed'] = array(
'url' => qa_path_html(qa_feed_request($feedpathprefix.(isset($categoryid) ? ('/'.qa_category_path_request($navcategories, $categoryid)) : ''))), 'url' => qa_path_html(qa_feed_request($feedpathprefix . (isset($categoryid) ? ('/' . qa_category_path_request($navcategories, $categoryid)) : ''))),
'label' => strip_tags($sometitle), 'label' => strip_tags($sometitle),
); );
return $qa_content; return $qa_content;
}
/**
* Return the sub navigation structure common to question listing pages
* @param $sort
* @param $categoryslugs
* @return array
*/
function qa_qs_sub_navigation($sort, $categoryslugs)
{
$request = 'questions';
if (isset($categoryslugs)) {
foreach ($categoryslugs as $slug) {
$request .= '/' . $slug;
}
} }
$navigation = array(
function qa_qs_sub_navigation($sort, $categoryslugs)
/*
Return the sub navigation structure common to question listing pages
*/
{
$request='questions';
if (isset($categoryslugs))
foreach ($categoryslugs as $slug)
$request.='/'.$slug;
$navigation=array(
'recent' => array( 'recent' => array(
'label' => qa_lang('main/nav_most_recent'), 'label' => qa_lang('main/nav_most_recent'),
'url' => qa_path_html($request), 'url' => qa_path_html($request),
...@@ -162,29 +182,34 @@ ...@@ -162,29 +182,34 @@
); );
if (isset($navigation[$sort])) if (isset($navigation[$sort]))
$navigation[$sort]['selected']=true; $navigation[$sort]['selected'] = true;
else else
$navigation['recent']['selected']=true; $navigation['recent']['selected'] = true;
if (!qa_opt('do_count_q_views')) if (!qa_opt('do_count_q_views'))
unset($navigation['views']); unset($navigation['views']);
return $navigation; return $navigation;
}
/**
* Return the sub navigation structure common to unanswered pages
* @param $by
* @param $categoryslugs
* @return array
*/
function qa_unanswered_sub_navigation($by, $categoryslugs)
{
$request = 'unanswered';
if (isset($categoryslugs)) {
foreach ($categoryslugs as $slug) {
$request .= '/' . $slug;
}
} }
$navigation = array(
function qa_unanswered_sub_navigation($by, $categoryslugs)
/*
Return the sub navigation structure common to unanswered pages
*/
{
$request='unanswered';
if (isset($categoryslugs))
foreach ($categoryslugs as $slug)
$request.='/'.$slug;
$navigation=array(
'by-answers' => array( 'by-answers' => array(
'label' => qa_lang('main/nav_no_answer'), 'label' => qa_lang('main/nav_no_answer'),
'url' => qa_path_html($request), 'url' => qa_path_html($request),
...@@ -201,18 +226,13 @@ ...@@ -201,18 +226,13 @@
), ),
); );
if (isset($navigation['by-'.$by])) if (isset($navigation['by-' . $by]))
$navigation['by-'.$by]['selected']=true; $navigation['by-' . $by]['selected'] = true;
else else
$navigation['by-answers']['selected']=true; $navigation['by-answers']['selected'] = true;
if (!qa_opt('voting_on_as')) if (!qa_opt('voting_on_as'))
unset($navigation['by-upvotes']); unset($navigation['by-upvotes']);
return $navigation; return $navigation;
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -61,26 +61,28 @@ if (!defined('QA_VERSION')) { // don't allow this page to be requested directly ...@@ -61,26 +61,28 @@ if (!defined('QA_VERSION')) { // don't allow this page to be requested directly
exit; exit;
} }
require_once QA_INCLUDE_DIR.'db/recalc.php'; require_once QA_INCLUDE_DIR . 'db/recalc.php';
require_once QA_INCLUDE_DIR.'db/post-create.php'; require_once QA_INCLUDE_DIR . 'db/post-create.php';
require_once QA_INCLUDE_DIR.'db/points.php'; require_once QA_INCLUDE_DIR . 'db/points.php';
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR.'db/admin.php'; require_once QA_INCLUDE_DIR . 'db/admin.php';
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR.'app/options.php'; require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR.'app/post-create.php'; require_once QA_INCLUDE_DIR . 'app/post-create.php';
require_once QA_INCLUDE_DIR.'app/post-update.php'; require_once QA_INCLUDE_DIR . 'app/post-update.php';
/** /**
* Advance the recalculation operation represented by $state by a single step. * Advance the recalculation operation represented by $state by a single step.
* $state can also be the name of a recalculation operation on its own. * $state can also be the name of a recalculation operation on its own.
* @param $state
* @return bool
*/ */
function qa_recalc_perform_step(&$state) function qa_recalc_perform_step(&$state)
{ {
$continue=false; $continue = false;
@list($operation, $length, $next, $done)=explode("\t", $state); @list($operation, $length, $next, $done) = explode("\t", $state);
switch ($operation) { switch ($operation) {
case 'doreindexcontent': case 'doreindexcontent':
...@@ -88,31 +90,32 @@ function qa_recalc_perform_step(&$state) ...@@ -88,31 +90,32 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doreindexcontent_pagereindex': case 'doreindexcontent_pagereindex':
$pages=qa_db_pages_get_for_reindexing($next, 10); $pages = qa_db_pages_get_for_reindexing($next, 10);
if (count($pages)) { if (count($pages)) {
require_once QA_INCLUDE_DIR.'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
$lastpageid=max(array_keys($pages)); $lastpageid = max(array_keys($pages));
foreach ($pages as $pageid => $page) foreach ($pages as $pageid => $page) {
if (!($page['flags'] & QA_PAGE_FLAGS_EXTERNAL)) { if (!($page['flags'] & QA_PAGE_FLAGS_EXTERNAL)) {
$searchmodules=qa_load_modules_with('search', 'unindex_page'); $searchmodules = qa_load_modules_with('search', 'unindex_page');
foreach ($searchmodules as $searchmodule) foreach ($searchmodules as $searchmodule)
$searchmodule->unindex_page($pageid); $searchmodule->unindex_page($pageid);
$searchmodules=qa_load_modules_with('search', 'index_page'); $searchmodules = qa_load_modules_with('search', 'index_page');
if (count($searchmodules)) { if (count($searchmodules)) {
$indextext=qa_viewer_text($page['content'], 'html'); $indextext = qa_viewer_text($page['content'], 'html');
foreach ($searchmodules as $searchmodule) foreach ($searchmodules as $searchmodule)
$searchmodule->index_page($pageid, $page['tags'], $page['heading'], $page['content'], 'html', $indextext); $searchmodule->index_page($pageid, $page['tags'], $page['heading'], $page['content'], 'html', $indextext);
} }
} }
}
$next=1+$lastpageid; $next = 1 + $lastpageid;
$done+=count($pages); $done += count($pages);
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'doreindexcontent_postcount'); qa_recalc_transition($state, 'doreindexcontent_postcount');
...@@ -127,12 +130,12 @@ function qa_recalc_perform_step(&$state) ...@@ -127,12 +130,12 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doreindexcontent_postreindex': case 'doreindexcontent_postreindex':
$posts=qa_db_posts_get_for_reindexing($next, 10); $posts = qa_db_posts_get_for_reindexing($next, 10);
if (count($posts)) { if (count($posts)) {
require_once QA_INCLUDE_DIR.'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
$lastpostid=max(array_keys($posts)); $lastpostid = max(array_keys($posts));
qa_db_prepare_for_reindexing($next, $lastpostid); qa_db_prepare_for_reindexing($next, $lastpostid);
qa_suspend_update_counts(); qa_suspend_update_counts();
...@@ -143,9 +146,9 @@ function qa_recalc_perform_step(&$state) ...@@ -143,9 +146,9 @@ function qa_recalc_perform_step(&$state)
$post['format'], qa_viewer_text($post['content'], $post['format']), $post['tags'], $post['categoryid']); $post['format'], qa_viewer_text($post['content'], $post['format']), $post['tags'], $post['categoryid']);
} }
$next=1+$lastpostid; $next = 1 + $lastpostid;
$done+=count($posts); $done += count($posts);
$continue=true; $continue = true;
} else { } else {
qa_db_truncate_indexes($next); qa_db_truncate_indexes($next);
...@@ -154,16 +157,16 @@ function qa_recalc_perform_step(&$state) ...@@ -154,16 +157,16 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doreindexposts_wordcount': case 'doreindexposts_wordcount':
$wordids=qa_db_words_prepare_for_recounting($next, 1000); $wordids = qa_db_words_prepare_for_recounting($next, 1000);
if (count($wordids)) { if (count($wordids)) {
$lastwordid=max($wordids); $lastwordid = max($wordids);
qa_db_words_recount($next, $lastwordid); qa_db_words_recount($next, $lastwordid);
$next=1+$lastwordid; $next = 1 + $lastwordid;
$done+=count($wordids); $done += count($wordids);
$continue=true; $continue = true;
} else { } else {
qa_db_tagcount_update(); // this is quick so just do it here qa_db_tagcount_update(); // this is quick so just do it here
...@@ -186,32 +189,32 @@ function qa_recalc_perform_step(&$state) ...@@ -186,32 +189,32 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecountposts_votecount': case 'dorecountposts_votecount':
$postids=qa_db_posts_get_for_recounting($next, 1000); $postids = qa_db_posts_get_for_recounting($next, 1000);
if (count($postids)) { if (count($postids)) {
$lastpostid=max($postids); $lastpostid = max($postids);
qa_db_posts_votes_recount($next, $lastpostid); qa_db_posts_votes_recount($next, $lastpostid);
$next=1+$lastpostid; $next = 1 + $lastpostid;
$done+=count($postids); $done += count($postids);
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dorecountposts_acount'); qa_recalc_transition($state, 'dorecountposts_acount');
break; break;
case 'dorecountposts_acount': case 'dorecountposts_acount':
$postids=qa_db_posts_get_for_recounting($next, 1000); $postids = qa_db_posts_get_for_recounting($next, 1000);
if (count($postids)) { if (count($postids)) {
$lastpostid=max($postids); $lastpostid = max($postids);
qa_db_posts_answers_recount($next, $lastpostid); qa_db_posts_answers_recount($next, $lastpostid);
$next=1+$lastpostid; $next = 1 + $lastpostid;
$done+=count($postids); $done += count($postids);
$continue=true; $continue = true;
} else { } else {
qa_db_unupaqcount_update(); qa_db_unupaqcount_update();
...@@ -230,22 +233,22 @@ function qa_recalc_perform_step(&$state) ...@@ -230,22 +233,22 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecalcpoints_recalc': case 'dorecalcpoints_recalc':
$recalccount=10; $recalccount = 10;
$userids=qa_db_users_get_for_recalc_points($next, $recalccount+1); // get one extra so we know where to start from next $userids = qa_db_users_get_for_recalc_points($next, $recalccount + 1); // get one extra so we know where to start from next
$gotcount=count($userids); $gotcount = count($userids);
$recalccount=min($recalccount, $gotcount); // can't recalc more than we got $recalccount = min($recalccount, $gotcount); // can't recalc more than we got
if ($recalccount>0) { if ($recalccount > 0) {
$lastuserid=$userids[$recalccount-1]; $lastuserid = $userids[$recalccount - 1];
qa_db_users_recalc_points($next, $lastuserid); qa_db_users_recalc_points($next, $lastuserid);
$done+=$recalccount; $done += $recalccount;
} else } else
$lastuserid=$next; // for truncation $lastuserid = $next; // for truncation
if ($gotcount>$recalccount) { // more left to do if ($gotcount > $recalccount) { // more left to do
$next=$userids[$recalccount]; // start next round at first one not recalculated $next = $userids[$recalccount]; // start next round at first one not recalculated
$continue=true; $continue = true;
} else { } else {
qa_db_truncate_userpoints($lastuserid); qa_db_truncate_userpoints($lastuserid);
...@@ -264,20 +267,20 @@ function qa_recalc_perform_step(&$state) ...@@ -264,20 +267,20 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorefillevents_refill': case 'dorefillevents_refill':
$questionids=qa_db_qs_get_for_event_refilling($next, 1); $questionids = qa_db_qs_get_for_event_refilling($next, 1);
if (count($questionids)) { if (count($questionids)) {
require_once QA_INCLUDE_DIR.'app/events.php'; require_once QA_INCLUDE_DIR . 'app/events.php';
require_once QA_INCLUDE_DIR.'app/updates.php'; require_once QA_INCLUDE_DIR . 'app/updates.php';
require_once QA_INCLUDE_DIR.'util/sort.php'; require_once QA_INCLUDE_DIR . 'util/sort.php';
$lastquestionid=max($questionids); $lastquestionid = max($questionids);
foreach ($questionids as $questionid) { foreach ($questionids as $questionid) {
// Retrieve all posts relating to this question // Retrieve all posts relating to this question
list($question, $childposts, $achildposts)=qa_db_select_with_pending( list($question, $childposts, $achildposts) = qa_db_select_with_pending(
qa_db_full_post_selectspec(null, $questionid), qa_db_full_post_selectspec(null, $questionid),
qa_db_full_child_posts_selectspec(null, $questionid), qa_db_full_child_posts_selectspec(null, $questionid),
qa_db_full_a_child_posts_selectspec(null, $questionid) qa_db_full_a_child_posts_selectspec(null, $questionid)
...@@ -285,27 +288,27 @@ function qa_recalc_perform_step(&$state) ...@@ -285,27 +288,27 @@ function qa_recalc_perform_step(&$state)
// Merge all posts while preserving keys as postids // Merge all posts while preserving keys as postids
$posts=array($questionid => $question); $posts = array($questionid => $question);
foreach ($childposts as $postid => $post) foreach ($childposts as $postid => $post)
$posts[$postid]=$post; $posts[$postid] = $post;
foreach ($achildposts as $postid => $post) foreach ($achildposts as $postid => $post)
$posts[$postid]=$post; $posts[$postid] = $post;
// Creation and editing of each post // Creation and editing of each post
foreach ($posts as $postid => $post) { foreach ($posts as $postid => $post) {
$followonq=($post['basetype']=='Q') && ($postid!=$questionid); $followonq = ($post['basetype'] == 'Q') && ($postid != $questionid);
if ($followonq) if ($followonq)
$updatetype=QA_UPDATE_FOLLOWS; $updatetype = QA_UPDATE_FOLLOWS;
elseif ( ($post['basetype']=='C') && (@$posts[$post['parentid']]['basetype']=='Q') ) elseif (($post['basetype'] == 'C') && (@$posts[$post['parentid']]['basetype'] == 'Q'))
$updatetype=QA_UPDATE_C_FOR_Q; $updatetype = QA_UPDATE_C_FOR_Q;
elseif ( ($post['basetype']=='C') && (@$posts[$post['parentid']]['basetype']=='A') ) elseif (($post['basetype'] == 'C') && (@$posts[$post['parentid']]['basetype'] == 'A'))
$updatetype=QA_UPDATE_C_FOR_A; $updatetype = QA_UPDATE_C_FOR_A;
else else
$updatetype=null; $updatetype = null;
qa_create_event_for_q_user($questionid, $postid, $updatetype, $post['userid'], @$posts[$post['parentid']]['userid'], $post['created']); qa_create_event_for_q_user($questionid, $postid, $updatetype, $post['userid'], @$posts[$post['parentid']]['userid'], $post['created']);
...@@ -320,33 +323,33 @@ function qa_recalc_perform_step(&$state) ...@@ -320,33 +323,33 @@ function qa_recalc_perform_step(&$state)
// Collect comment threads // Collect comment threads
$parentidcomments=array(); $parentidcomments = array();
foreach ($posts as $postid => $post) foreach ($posts as $postid => $post)
if ($post['basetype']=='C') if ($post['basetype'] == 'C')
$parentidcomments[$post['parentid']][$postid]=$post; $parentidcomments[$post['parentid']][$postid] = $post;
// For each comment thread, notify all previous comment authors of each comment in the thread (could get slow) // For each comment thread, notify all previous comment authors of each comment in the thread (could get slow)
foreach ($parentidcomments as $parentid => $comments) { foreach ($parentidcomments as $parentid => $comments) {
$keyuserids=array(); $keyuserids = array();
qa_sort_by($comments, 'created'); qa_sort_by($comments, 'created');
foreach ($comments as $comment) { foreach ($comments as $comment) {
foreach ($keyuserids as $keyuserid => $dummy) foreach ($keyuserids as $keyuserid => $dummy)
if ( ($keyuserid != $comment['userid']) && ($keyuserid != @$posts[$parentid]['userid']) ) if (($keyuserid != $comment['userid']) && ($keyuserid != @$posts[$parentid]['userid']))
qa_db_event_create_not_entity($keyuserid, $questionid, $comment['postid'], QA_UPDATE_FOLLOWS, $comment['userid'], $comment['created']); qa_db_event_create_not_entity($keyuserid, $questionid, $comment['postid'], QA_UPDATE_FOLLOWS, $comment['userid'], $comment['created']);
if (isset($comment['userid'])) if (isset($comment['userid']))
$keyuserids[$comment['userid']]=true; $keyuserids[$comment['userid']] = true;
} }
} }
} }
$next=1+$lastquestionid; $next = 1 + $lastquestionid;
$done+=count($questionids); $done += count($questionids);
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dorefillevents_complete'); qa_recalc_transition($state, 'dorefillevents_complete');
...@@ -364,17 +367,17 @@ function qa_recalc_perform_step(&$state) ...@@ -364,17 +367,17 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecalccategories_postupdate': case 'dorecalccategories_postupdate':
$postids=qa_db_posts_get_for_recategorizing($next, 100); $postids = qa_db_posts_get_for_recategorizing($next, 100);
if (count($postids)) { if (count($postids)) {
$lastpostid=max($postids); $lastpostid = max($postids);
qa_db_posts_recalc_categoryid($next, $lastpostid); qa_db_posts_recalc_categoryid($next, $lastpostid);
qa_db_posts_calc_category_path($next, $lastpostid); qa_db_posts_calc_category_path($next, $lastpostid);
$next=1+$lastpostid; $next = 1 + $lastpostid;
$done+=count($postids); $done += count($postids);
$continue=true; $continue = true;
} else { } else {
qa_recalc_transition($state, 'dorecalccategories_recount'); qa_recalc_transition($state, 'dorecalccategories_recount');
...@@ -382,17 +385,17 @@ function qa_recalc_perform_step(&$state) ...@@ -382,17 +385,17 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecalccategories_recount': case 'dorecalccategories_recount':
$categoryids=qa_db_categories_get_for_recalcs($next, 10); $categoryids = qa_db_categories_get_for_recalcs($next, 10);
if (count($categoryids)) { if (count($categoryids)) {
$lastcategoryid=max($categoryids); $lastcategoryid = max($categoryids);
foreach ($categoryids as $categoryid) foreach ($categoryids as $categoryid)
qa_db_ifcategory_qcount_update($categoryid); qa_db_ifcategory_qcount_update($categoryid);
$next=1+$lastcategoryid; $next = 1 + $lastcategoryid;
$done+=count($categoryids); $done += count($categoryids);
$continue=true; $continue = true;
} else { } else {
qa_recalc_transition($state, 'dorecalccategories_backpaths'); qa_recalc_transition($state, 'dorecalccategories_backpaths');
...@@ -400,16 +403,16 @@ function qa_recalc_perform_step(&$state) ...@@ -400,16 +403,16 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecalccategories_backpaths': case 'dorecalccategories_backpaths':
$categoryids=qa_db_categories_get_for_recalcs($next, 10); $categoryids = qa_db_categories_get_for_recalcs($next, 10);
if (count($categoryids)) { if (count($categoryids)) {
$lastcategoryid=max($categoryids); $lastcategoryid = max($categoryids);
qa_db_categories_recalc_backpaths($next, $lastcategoryid); qa_db_categories_recalc_backpaths($next, $lastcategoryid);
$next=1+$lastcategoryid; $next = 1 + $lastcategoryid;
$done+=count($categoryids); $done += count($categoryids);
$continue=true; $continue = true;
} else { } else {
qa_recalc_transition($state, 'dorecalccategories_complete'); qa_recalc_transition($state, 'dorecalccategories_complete');
...@@ -421,54 +424,54 @@ function qa_recalc_perform_step(&$state) ...@@ -421,54 +424,54 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dodeletehidden_comments': case 'dodeletehidden_comments':
$posts=qa_db_posts_get_for_deleting('C', $next, 1); $posts = qa_db_posts_get_for_deleting('C', $next, 1);
if (count($posts)) { if (count($posts)) {
require_once QA_INCLUDE_DIR.'app/posts.php'; require_once QA_INCLUDE_DIR . 'app/posts.php';
$postid=$posts[0]; $postid = $posts[0];
qa_post_delete($postid); qa_post_delete($postid);
$next=1+$postid; $next = 1 + $postid;
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dodeletehidden_answers'); qa_recalc_transition($state, 'dodeletehidden_answers');
break; break;
case 'dodeletehidden_answers': case 'dodeletehidden_answers':
$posts=qa_db_posts_get_for_deleting('A', $next, 1); $posts = qa_db_posts_get_for_deleting('A', $next, 1);
if (count($posts)) { if (count($posts)) {
require_once QA_INCLUDE_DIR.'app/posts.php'; require_once QA_INCLUDE_DIR . 'app/posts.php';
$postid=$posts[0]; $postid = $posts[0];
qa_post_delete($postid); qa_post_delete($postid);
$next=1+$postid; $next = 1 + $postid;
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dodeletehidden_questions'); qa_recalc_transition($state, 'dodeletehidden_questions');
break; break;
case 'dodeletehidden_questions': case 'dodeletehidden_questions':
$posts=qa_db_posts_get_for_deleting('Q', $next, 1); $posts = qa_db_posts_get_for_deleting('Q', $next, 1);
if (count($posts)) { if (count($posts)) {
require_once QA_INCLUDE_DIR.'app/posts.php'; require_once QA_INCLUDE_DIR . 'app/posts.php';
$postid=$posts[0]; $postid = $posts[0];
qa_post_delete($postid); qa_post_delete($postid);
$next=1+$postid; $next = 1 + $postid;
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dodeletehidden_complete'); qa_recalc_transition($state, 'dodeletehidden_complete');
...@@ -479,18 +482,18 @@ function qa_recalc_perform_step(&$state) ...@@ -479,18 +482,18 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doblobstodisk_move': case 'doblobstodisk_move':
$blob=qa_db_get_next_blob_in_db($next); $blob = qa_db_get_next_blob_in_db($next);
if (isset($blob)) { if (isset($blob)) {
require_once QA_INCLUDE_DIR.'app/blobs.php'; require_once QA_INCLUDE_DIR . 'app/blobs.php';
require_once QA_INCLUDE_DIR.'db/blobs.php'; require_once QA_INCLUDE_DIR . 'db/blobs.php';
if (qa_write_blob_file($blob['blobid'], $blob['content'], $blob['format'])) if (qa_write_blob_file($blob['blobid'], $blob['content'], $blob['format']))
qa_db_blob_set_content($blob['blobid'], null); qa_db_blob_set_content($blob['blobid'], null);
$next=1+$blob['blobid']; $next = 1 + $blob['blobid'];
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'doblobstodisk_complete'); qa_recalc_transition($state, 'doblobstodisk_complete');
...@@ -501,108 +504,112 @@ function qa_recalc_perform_step(&$state) ...@@ -501,108 +504,112 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doblobstodb_move': case 'doblobstodb_move':
$blob=qa_db_get_next_blob_on_disk($next); $blob = qa_db_get_next_blob_on_disk($next);
if (isset($blob)) { if (isset($blob)) {
require_once QA_INCLUDE_DIR.'app/blobs.php'; require_once QA_INCLUDE_DIR . 'app/blobs.php';
require_once QA_INCLUDE_DIR.'db/blobs.php'; require_once QA_INCLUDE_DIR . 'db/blobs.php';
$content=qa_read_blob_file($blob['blobid'], $blob['format']); $content = qa_read_blob_file($blob['blobid'], $blob['format']);
qa_db_blob_set_content($blob['blobid'], $content); qa_db_blob_set_content($blob['blobid'], $content);
qa_delete_blob_file($blob['blobid'], $blob['format']); qa_delete_blob_file($blob['blobid'], $blob['format']);
$next=1+$blob['blobid']; $next = 1 + $blob['blobid'];
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'doblobstodb_complete'); qa_recalc_transition($state, 'doblobstodb_complete');
break; break;
default: default:
$state=''; $state = '';
break; break;
} }
if ($continue) if ($continue)
$state=$operation."\t".$length."\t".$next."\t".$done; $state = $operation . "\t" . $length . "\t" . $next . "\t" . $done;
return $continue && ($done<$length); return $continue && ($done < $length);
} }
/** /**
* Change the $state to represent the beginning of a new $operation * Change the $state to represent the beginning of a new $operation
* @param $state
* @param $operation
*/ */
function qa_recalc_transition(&$state, $operation) function qa_recalc_transition(&$state, $operation)
{ {
$length=qa_recalc_stage_length($operation); $length = qa_recalc_stage_length($operation);
$next=(QA_FINAL_EXTERNAL_USERS && ($operation=='dorecalcpoints_recalc')) ? '' : 0; $next = (QA_FINAL_EXTERNAL_USERS && ($operation == 'dorecalcpoints_recalc')) ? '' : 0;
$done=0; $done = 0;
$state=$operation."\t".$length."\t".$next."\t".$done; $state = $operation . "\t" . $length . "\t" . $next . "\t" . $done;
} }
/** /**
* Return how many steps there will be in recalculation $operation * Return how many steps there will be in recalculation $operation
* @param $operation
* @return int
*/ */
function qa_recalc_stage_length($operation) function qa_recalc_stage_length($operation)
{ {
switch ($operation) { switch ($operation) {
case 'doreindexcontent_pagereindex': case 'doreindexcontent_pagereindex':
$length=qa_db_count_pages(); $length = qa_db_count_pages();
break; break;
case 'doreindexcontent_postreindex': case 'doreindexcontent_postreindex':
$length=qa_opt('cache_qcount')+qa_opt('cache_acount')+qa_opt('cache_ccount'); $length = qa_opt('cache_qcount') + qa_opt('cache_acount') + qa_opt('cache_ccount');
break; break;
case 'doreindexposts_wordcount': case 'doreindexposts_wordcount':
$length=qa_db_count_words(); $length = qa_db_count_words();
break; break;
case 'dorecalcpoints_recalc': case 'dorecalcpoints_recalc':
$length=qa_opt('cache_userpointscount'); $length = qa_opt('cache_userpointscount');
break; break;
case 'dorecountposts_votecount': case 'dorecountposts_votecount':
case 'dorecountposts_acount': case 'dorecountposts_acount':
case 'dorecalccategories_postupdate': case 'dorecalccategories_postupdate':
$length=qa_db_count_posts(); $length = qa_db_count_posts();
break; break;
case 'dorefillevents_refill': case 'dorefillevents_refill':
$length=qa_opt('cache_qcount')+qa_db_count_posts('Q_HIDDEN'); $length = qa_opt('cache_qcount') + qa_db_count_posts('Q_HIDDEN');
break; break;
case 'dorecalccategories_recount': case 'dorecalccategories_recount':
case 'dorecalccategories_backpaths': case 'dorecalccategories_backpaths':
$length=qa_db_count_categories(); $length = qa_db_count_categories();
break; break;
case 'dodeletehidden_comments': case 'dodeletehidden_comments':
$length=count(qa_db_posts_get_for_deleting('C')); $length = count(qa_db_posts_get_for_deleting('C'));
break; break;
case 'dodeletehidden_answers': case 'dodeletehidden_answers':
$length=count(qa_db_posts_get_for_deleting('A')); $length = count(qa_db_posts_get_for_deleting('A'));
break; break;
case 'dodeletehidden_questions': case 'dodeletehidden_questions':
$length=count(qa_db_posts_get_for_deleting('Q')); $length = count(qa_db_posts_get_for_deleting('Q'));
break; break;
case 'doblobstodisk_move': case 'doblobstodisk_move':
$length=qa_db_count_blobs_in_db(); $length = qa_db_count_blobs_in_db();
break; break;
case 'doblobstodb_move': case 'doblobstodb_move':
$length=qa_db_count_blobs_on_disk(); $length = qa_db_count_blobs_on_disk();
break; break;
default: default:
$length=0; $length = 0;
break; break;
} }
...@@ -624,13 +631,15 @@ function qa_recalc_progress_lang($langId, $progress, $total) ...@@ -624,13 +631,15 @@ function qa_recalc_progress_lang($langId, $progress, $total)
{ {
return strtr(qa_lang($langId), array( return strtr(qa_lang($langId), array(
'^1' => qa_format_number($progress), '^1' => qa_format_number($progress),
'^2' => qa_format_number($total) '^2' => qa_format_number($total),
)); ));
} }
/** /**
* Return a string which gives a user-viewable version of $state * Return a string which gives a user-viewable version of $state
* @param $state
* @return string
*/ */
function qa_recalc_get_message($state) function qa_recalc_get_message($state)
{ {
...@@ -638,8 +647,8 @@ function qa_recalc_get_message($state) ...@@ -638,8 +647,8 @@ function qa_recalc_get_message($state)
@list($operation, $length, $next, $done) = explode("\t", $state); @list($operation, $length, $next, $done) = explode("\t", $state);
$done = (int) $done; $done = (int)$done;
$length = (int) $length; $length = (int)$length;
switch ($operation) { switch ($operation) {
case 'doreindexcontent_postcount': case 'doreindexcontent_postcount':
......
...@@ -20,67 +20,73 @@ ...@@ -20,67 +20,73 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
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
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
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
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.
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 // Identify which search module should be used
$searchmodules=qa_load_modules_with('search', 'process_search'); $searchmodules = qa_load_modules_with('search', 'process_search');
if (!count($searchmodules)) if (!count($searchmodules))
qa_fatal_error('No search engine is available'); qa_fatal_error('No search engine is available');
$module=reset($searchmodules); // use first one by default $module = reset($searchmodules); // use first one by default
if (count($searchmodules)>1) { if (count($searchmodules) > 1) {
$tryname=qa_opt('search_module'); // use chosen one if it's available $tryname = qa_opt('search_module'); // use chosen one if it's available
if (isset($searchmodules[$tryname])) if (isset($searchmodules[$tryname]))
$module=$searchmodules[$tryname]; $module = $searchmodules[$tryname];
} }
// Get the results // Get the results
$results=$module->process_search($query, $start, $count, $userid, $absoluteurls, $fullcontent); $results = $module->process_search($query, $start, $count, $userid, $absoluteurls, $fullcontent);
// Work out what additional information (if any) we need to retrieve for the results // Work out what additional information (if any) we need to retrieve for the results
$keypostidgetfull=array(); $keypostidgetfull = array();
$keypostidgettype=array(); $keypostidgettype = array();
$keypostidgetquestion=array(); $keypostidgetquestion = array();
$keypageidgetpage=array(); $keypageidgetpage = array();
foreach ($results as $result) { foreach ($results as $result) {
if (isset($result['question_postid']) && !isset($result['question'])) if (isset($result['question_postid']) && !isset($result['question']))
$keypostidgetfull[$result['question_postid']]=true; $keypostidgetfull[$result['question_postid']] = true;
if (isset($result['match_postid'])) { if (isset($result['match_postid'])) {
if (!( (isset($result['question_postid'])) || (isset($result['question'])) )) if (!((isset($result['question_postid'])) || (isset($result['question']))))
$keypostidgetquestion[$result['match_postid']]=true; // we can also get $result['match_type'] from this $keypostidgetquestion[$result['match_postid']] = true; // we can also get $result['match_type'] from this
elseif (!isset($result['match_type'])) elseif (!isset($result['match_type']))
$keypostidgettype[$result['match_postid']]=true; $keypostidgettype[$result['match_postid']] = true;
} }
if (isset($result['page_pageid']) && !isset($result['page'])) if (isset($result['page_pageid']) && !isset($result['page']))
$keypageidgetpage[$result['page_pageid']]=true; $keypageidgetpage[$result['page_pageid']] = true;
} }
// Perform the appropriate database queries // Perform the appropriate database queries
list($postidfull, $postidtype, $postidquestion, $pageidpage)=qa_db_select_with_pending( list($postidfull, $postidtype, $postidquestion, $pageidpage) = qa_db_select_with_pending(
count($keypostidgetfull) ? qa_db_posts_selectspec($userid, array_keys($keypostidgetfull), $fullcontent) : null, count($keypostidgetfull) ? qa_db_posts_selectspec($userid, array_keys($keypostidgetfull), $fullcontent) : null,
count($keypostidgettype) ? qa_db_posts_basetype_selectspec(array_keys($keypostidgettype)) : 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($keypostidgetquestion) ? qa_db_posts_to_qs_selectspec($userid, array_keys($keypostidgetquestion), $fullcontent) : null,
...@@ -91,50 +97,45 @@ ...@@ -91,50 +97,45 @@
foreach ($results as $key => $result) { foreach ($results as $key => $result) {
if (isset($result['question_postid']) && !isset($result['question'])) if (isset($result['question_postid']) && !isset($result['question']))
if (@$postidfull[$result['question_postid']]['basetype']=='Q') if (@$postidfull[$result['question_postid']]['basetype'] == 'Q')
$result['question']=@$postidfull[$result['question_postid']]; $result['question'] = @$postidfull[$result['question_postid']];
if (isset($result['match_postid'])) { if (isset($result['match_postid'])) {
if (!( (isset($result['question_postid'])) || (isset($result['question'])) )) { if (!(isset($result['question_postid']) || isset($result['question']))) {
$result['question']=@$postidquestion[$result['match_postid']]; $result['question'] = @$postidquestion[$result['match_postid']];
if (!isset($result['match_type'])) if (!isset($result['match_type']))
$result['match_type']=@$result['question']['obasetype']; $result['match_type'] = @$result['question']['obasetype'];
} elseif (!isset($result['match_type'])) } elseif (!isset($result['match_type']))
$result['match_type']=@$postidtype[$result['match_postid']]; $result['match_type'] = @$postidtype[$result['match_postid']];
} }
if (isset($result['question']) && !isset($result['question_postid'])) if (isset($result['question']) && !isset($result['question_postid']))
$result['question_postid']=$result['question']['postid']; $result['question_postid'] = $result['question']['postid'];
if (isset($result['page_pageid']) && !isset($result['page'])) if (isset($result['page_pageid']) && !isset($result['page']))
$result['page']=@$pageidpage[$result['page_pageid']]; $result['page'] = @$pageidpage[$result['page_pageid']];
if (!isset($result['title'])) { if (!isset($result['title'])) {
if (isset($result['question'])) if (isset($result['question']))
$result['title']=$result['question']['title']; $result['title'] = $result['question']['title'];
elseif (isset($result['page'])) elseif (isset($result['page']))
$result['title']=$result['page']['heading']; $result['title'] = $result['page']['heading'];
} }
if (!isset($result['url'])) { if (!isset($result['url'])) {
if (isset($result['question'])) if (isset($result['question']))
$result['url']=qa_q_path($result['question']['postid'], $result['question']['title'], $result['url'] = qa_q_path($result['question']['postid'], $result['question']['title'],
$absoluteurls, @$result['match_type'], @$result['match_postid']); $absoluteurls, @$result['match_type'], @$result['match_postid']);
elseif (isset($result['page'])) elseif (isset($result['page']))
$result['url']=qa_path($result['page']['tags'], null, qa_opt('site_url')); $result['url'] = qa_path($result['page']['tags'], null, qa_opt('site_url'));
} }
$results[$key]=$result; $results[$key] = $result;
} }
// Return the results // Return the results
return $results; return $results;
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,39 +20,35 @@ ...@@ -20,39 +20,35 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; 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_QUESTION', 'Q');
define('QA_ENTITY_USER', 'U'); define('QA_ENTITY_USER', 'U');
define('QA_ENTITY_TAG', 'T'); define('QA_ENTITY_TAG', 'T');
define('QA_ENTITY_CATEGORY', 'C'); define('QA_ENTITY_CATEGORY', 'C');
define('QA_ENTITY_NONE', '-'); 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_CATEGORY', 'A'); // questions only, category changed
define('QA_UPDATE_CLOSED', 'C'); // questions only, closed or reopened define('QA_UPDATE_CLOSED', 'C'); // questions only, closed or reopened
define('QA_UPDATE_CONTENT', 'E'); // title or content edited 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_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_SELECTED', 'S'); // answers only, removed if unselected
define('QA_UPDATE_TAGS', 'T'); // questions only define('QA_UPDATE_TAGS', 'T'); // questions only
define('QA_UPDATE_TYPE', 'Y'); // e.g. answer to comment define('QA_UPDATE_TYPE', 'Y'); // e.g. answer to comment
define('QA_UPDATE_VISIBLE', 'H'); // hidden or reshown 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_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_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 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
...@@ -20,17 +20,17 @@ ...@@ -20,17 +20,17 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
function qa_get_max_upload_size() /**
/* * Return the maximum size of file that can be uploaded, based on database and PHP limits
Return the maximum size of file that can be uploaded, based on database and PHP limits */
*/ function qa_get_max_upload_size()
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$mindb = 16777215; // from MEDIUMBLOB column type $mindb = 16777215; // from MEDIUMBLOB column type
...@@ -39,39 +39,45 @@ ...@@ -39,39 +39,45 @@
$minphp = convert_to_bytes(substr($minphp, -1), $minphp); $minphp = convert_to_bytes(substr($minphp, -1), $minphp);
return min($mindb, $minphp); return min($mindb, $minphp);
} }
function qa_upload_file($localfilename, $sourcefilename, $maxfilesize=null, $onlyimage=false, $imagemaxwidth=null, $imagemaxheight=null) /**
/* * Move an uploaded image or other file into blob storage. Pass the $localfilename where the file is currently stored
Move an uploaded image or other file into blob storage. Pass the $localfilename where the file is currently stored * (temporarily) and the $sourcefilename of the file on the user's computer (if using PHP's usual file upload
(temporarily) and the $sourcefilename of the file on the user's computer (if using PHP's usual file upload * mechanism, these are obtained from $_FILES[..]['tmp_name'] and $_FILES[..]['name'] fields respectively). To apply a
mechanism, these are obtained from $_FILES[..]['tmp_name'] and $_FILES[..]['name'] fields respectively). To apply a * maximum file size (in bytes) beyond the general one, use $maxfilesize, otherwise set it to null. Set $onlyimage to
maximum file size (in bytes) beyond the general one, use $maxfilesize, otherwise set it to null. Set $onlyimage to * true if only image uploads (PNG, GIF, JPEG) are allowed. To apply a maximum width or height (in pixels) to uploaded
true if only image uploads (PNG, GIF, JPEG) are allowed. To apply a maximum width or height (in pixels) to uploaded * images, set $imagemaxwidth and $imagemaxheight. The function returns an array which may contain the following elements:
images, set $imagemaxwidth and $imagemaxheight. The function returns an array which may contain the following elements: *
* 'error' => a string containing an error, if one occurred
'error' => a string containing an error, if one occurred * 'format' => the format (file extension) of the blob created (all scaled images end up as 'jpeg')
'format' => the format (file extension) of the blob created (all scaled images end up as 'jpeg') * 'width' => if an image, the width in pixels of the blob created (after possible scaling)
'width' => if an image, the width in pixels of the blob created (after possible scaling) * 'height' => if an image, the height in pixels of the blob created (after possible scaling)
'height' => if an image, the height in pixels of the blob created (after possible scaling) * 'blobid' => the blobid that was created (if there was no error)
'blobid' => the blobid that was created (if there was no error) * 'bloburl' => the url that can be used to view/download the created blob (if there was no error)
'bloburl' => the url that can be used to view/download the created blob (if there was no error) * @param $localfilename
*/ * @param $sourcefilename
{ * @param $maxfilesize
* @param bool $onlyimage
* @param $imagemaxwidth
* @param $imagemaxheight
* @return array
*/
function qa_upload_file($localfilename, $sourcefilename, $maxfilesize = null, $onlyimage = false, $imagemaxwidth = null, $imagemaxheight = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$result=array(); $result = array();
// Check per-user upload limits // Check per-user upload limits
require_once QA_INCLUDE_DIR.'app/users.php'; require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR.'app/limits.php'; require_once QA_INCLUDE_DIR . 'app/limits.php';
switch (qa_user_permit_error(null, QA_LIMIT_UPLOADS)) switch (qa_user_permit_error(null, QA_LIMIT_UPLOADS)) {
{
case 'limit': case 'limit':
$result['error']=qa_lang('main/upload_limit'); $result['error'] = qa_lang('main/upload_limit');
return $result; return $result;
case false: case false:
...@@ -79,76 +85,77 @@ ...@@ -79,76 +85,77 @@
break; break;
default: default:
$result['error']=qa_lang('users/no_permission'); $result['error'] = qa_lang('users/no_permission');
return $result; return $result;
} }
// Check the uploaded file is not too large // Check the uploaded file is not too large
$filesize=filesize($localfilename); $filesize = filesize($localfilename);
if (isset($maxfilesize)) if (isset($maxfilesize))
$maxfilesize=min($maxfilesize, qa_get_max_upload_size()); $maxfilesize = min($maxfilesize, qa_get_max_upload_size());
else else
$maxfilesize=qa_get_max_upload_size(); $maxfilesize = qa_get_max_upload_size();
if ( ($filesize<=0) || ($filesize>$maxfilesize) ) { // if file was too big for PHP, $filesize will be zero if (($filesize <= 0) || ($filesize > $maxfilesize)) { // if file was too big for PHP, $filesize will be zero
$result['error']=qa_lang_sub('main/max_upload_size_x', qa_format_number($maxfilesize/1048576, 1).'MB'); $result['error'] = qa_lang_sub('main/max_upload_size_x', qa_format_number($maxfilesize / 1048576, 1) . 'MB');
return $result; return $result;
} }
// Find out what type of source file was uploaded and if appropriate, check it's an image and get preliminary size measure // Find out what type of source file was uploaded and if appropriate, check it's an image and get preliminary size measure
$pathinfo=pathinfo($sourcefilename); $pathinfo = pathinfo($sourcefilename);
$format=strtolower(@$pathinfo['extension']); $format = strtolower(@$pathinfo['extension']);
$isimage=($format=='png') || ($format=='gif') || ($format=='jpeg') || ($format=='jpg'); // allowed image extensions $isimage = ($format == 'png') || ($format == 'gif') || ($format == 'jpeg') || ($format == 'jpg'); // allowed image extensions
if ($isimage) { if ($isimage) {
$imagesize=@getimagesize($localfilename); $imagesize = @getimagesize($localfilename);
if (is_array($imagesize)) { if (is_array($imagesize)) {
$result['width']=$imagesize[0]; $result['width'] = $imagesize[0];
$result['height']=$imagesize[1]; $result['height'] = $imagesize[1];
switch ($imagesize['2']) { // reassign format based on actual content, if we can switch ($imagesize['2']) { // reassign format based on actual content, if we can
case IMAGETYPE_GIF: case IMAGETYPE_GIF:
$format='gif'; $format = 'gif';
break; break;
case IMAGETYPE_JPEG: case IMAGETYPE_JPEG:
$format='jpeg'; $format = 'jpeg';
break; break;
case IMAGETYPE_PNG: case IMAGETYPE_PNG:
$format='png'; $format = 'png';
break; break;
} }
} }
} }
$result['format']=$format; $result['format'] = $format;
if ($onlyimage) if ($onlyimage) {
if ( (!$isimage) || !is_array($imagesize) ) { if ((!$isimage) || !is_array($imagesize)) {
$result['error']=qa_lang_sub('main/image_not_read', 'GIF, JPG, PNG'); $result['error'] = qa_lang_sub('main/image_not_read', 'GIF, JPG, PNG');
return $result; return $result;
} }
}
// Read in the raw file contents // Read in the raw file contents
$content=file_get_contents($localfilename); $content = file_get_contents($localfilename);
// If appropriate, get more accurate image size and apply constraints to it // If appropriate, get more accurate image size and apply constraints to it
require_once QA_INCLUDE_DIR.'util/image.php'; require_once QA_INCLUDE_DIR . 'util/image.php';
if ($isimage && qa_has_gd_image()) { if ($isimage && qa_has_gd_image()) {
$image=@imagecreatefromstring($content); $image = @imagecreatefromstring($content);
if (is_resource($image)) { if (is_resource($image)) {
$result['width']=$width=imagesx($image); $result['width'] = $width = imagesx($image);
$result['height']=$height=imagesy($image); $result['height'] = $height = imagesy($image);
if (isset($imagemaxwidth) || isset($imagemaxheight)) if (isset($imagemaxwidth) || isset($imagemaxheight)) {
if (qa_image_constrain( if (qa_image_constrain(
$width, $height, $width, $height,
isset($imagemaxwidth) ? $imagemaxwidth : $width, isset($imagemaxwidth) ? $imagemaxwidth : $width,
...@@ -157,10 +164,11 @@ ...@@ -157,10 +164,11 @@
qa_gd_image_resize($image, $width, $height); qa_gd_image_resize($image, $width, $height);
if (is_resource($image)) { if (is_resource($image)) {
$content=qa_gd_image_jpeg($image); $content = qa_gd_image_jpeg($image);
$result['format']=$format='jpeg'; $result['format'] = $format = 'jpeg';
$result['width']=$width; $result['width'] = $width;
$result['height']=$height; $result['height'] = $height;
}
} }
} }
...@@ -171,34 +179,34 @@ ...@@ -171,34 +179,34 @@
// Create the blob and return // Create the blob and return
require_once QA_INCLUDE_DIR.'app/blobs.php'; require_once QA_INCLUDE_DIR . 'app/blobs.php';
$userid=qa_get_logged_in_userid(); $userid = qa_get_logged_in_userid();
$cookieid=isset($userid) ? qa_cookie_get() : qa_cookie_get_create(); $cookieid = isset($userid) ? qa_cookie_get() : qa_cookie_get_create();
$result['blobid']=qa_create_blob($content, $format, $sourcefilename, $userid, $cookieid, qa_remote_ip_address()); $result['blobid'] = qa_create_blob($content, $format, $sourcefilename, $userid, $cookieid, qa_remote_ip_address());
if (!isset($result['blobid'])) { if (!isset($result['blobid'])) {
$result['error']=qa_lang('main/general_error'); $result['error'] = qa_lang('main/general_error');
return $result; return $result;
} }
$result['bloburl']=qa_get_blob_url($result['blobid'], true); $result['bloburl'] = qa_get_blob_url($result['blobid'], true);
return $result; return $result;
} }
function qa_upload_file_one($maxfilesize=null, $onlyimage=false, $imagemaxwidth=null, $imagemaxheight=null) /**
/* * In response to a file upload, move the first uploaded file into blob storage. Other parameters are as for qa_upload_file(...)
In response to a file upload, move the first uploaded file into blob storage. Other parameters are as for qa_upload_file(...) * @param $maxfilesize
*/ * @param bool $onlyimage
{ * @param $imagemaxwidth
$file=reset($_FILES); * @param $imagemaxheight
* @return array
*/
function qa_upload_file_one($maxfilesize = null, $onlyimage = false, $imagemaxwidth = null, $imagemaxheight = null)
{
$file = reset($_FILES);
return qa_upload_file($file['tmp_name'], $file['name'], $maxfilesize, $onlyimage, $imagemaxwidth, $imagemaxheight); return qa_upload_file($file['tmp_name'], $file['name'], $maxfilesize, $onlyimage, $imagemaxwidth, $imagemaxheight);
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,151 +20,168 @@ ...@@ -20,151 +20,168 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
@define('QA_MIN_PASSWORD_LEN', 4); @define('QA_MIN_PASSWORD_LEN', 4);
@define('QA_NEW_PASSWORD_LEN', 8); // when resetting password @define('QA_NEW_PASSWORD_LEN', 8); // when resetting password
function qa_handle_email_filter(&$handle, &$email, $olduser=null) /**
/* * Return $errors fields for any invalid aspect of user-entered $handle (username) and $email. Works by calling through
Return $errors fields for any invalid aspect of user-entered $handle (username) and $email. Works by calling through * to all filter modules and also rejects existing values in database unless they belongs to $olduser (if set).
to all filter modules and also rejects existing values in database unless they belongs to $olduser (if set). * @param $handle
*/ * @param $email
{ * @param $olduser
require_once QA_INCLUDE_DIR.'db/users.php'; * @return array
require_once QA_INCLUDE_DIR.'util/string.php'; */
function qa_handle_email_filter(&$handle, &$email, $olduser = null)
{
require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
$errors=array(); $errors = array();
// sanitise 4-byte Unicode // sanitise 4-byte Unicode
$handle = qa_remove_utf8mb4($handle); $handle = qa_remove_utf8mb4($handle);
$filtermodules=qa_load_modules_with('filter', 'filter_handle'); $filtermodules = qa_load_modules_with('filter', 'filter_handle');
foreach ($filtermodules as $filtermodule) { foreach ($filtermodules as $filtermodule) {
$error=$filtermodule->filter_handle($handle, $olduser); $error = $filtermodule->filter_handle($handle, $olduser);
if (isset($error)) { if (isset($error)) {
$errors['handle']=$error; $errors['handle'] = $error;
break; break;
} }
} }
if (!isset($errors['handle'])) { // first test through filters, then check for duplicates here if (!isset($errors['handle'])) { // first test through filters, then check for duplicates here
$handleusers=qa_db_user_find_by_handle($handle); $handleusers = qa_db_user_find_by_handle($handle);
if (count($handleusers) && ( (!isset($olduser['userid'])) || (array_search($olduser['userid'], $handleusers)===false) ) ) if (count($handleusers) && ((!isset($olduser['userid'])) || (array_search($olduser['userid'], $handleusers) === false)))
$errors['handle']=qa_lang('users/handle_exists'); $errors['handle'] = qa_lang('users/handle_exists');
} }
$filtermodules=qa_load_modules_with('filter', 'filter_email'); $filtermodules = qa_load_modules_with('filter', 'filter_email');
$error=null; $error = null;
foreach ($filtermodules as $filtermodule) { foreach ($filtermodules as $filtermodule) {
$error=$filtermodule->filter_email($email, $olduser); $error = $filtermodule->filter_email($email, $olduser);
if (isset($error)) { if (isset($error)) {
$errors['email']=$error; $errors['email'] = $error;
break; break;
} }
} }
if (!isset($errors['email'])) { if (!isset($errors['email'])) {
$emailusers=qa_db_user_find_by_email($email); $emailusers = qa_db_user_find_by_email($email);
if (count($emailusers) && ( (!isset($olduser['userid'])) || (array_search($olduser['userid'], $emailusers)===false) ) ) if (count($emailusers) && ((!isset($olduser['userid'])) || (array_search($olduser['userid'], $emailusers) === false)))
$errors['email']=qa_lang('users/email_exists'); $errors['email'] = qa_lang('users/email_exists');
} }
return $errors; return $errors;
} }
function qa_handle_make_valid($handle) /**
/* * Make $handle valid and unique in the database - if $allowuserid is set, allow it to match that user only
Make $handle valid and unique in the database - if $allowuserid is set, allow it to match that user only * @param $handle
*/ * @return string
{ */
require_once QA_INCLUDE_DIR.'util/string.php'; function qa_handle_make_valid($handle)
require_once QA_INCLUDE_DIR.'db/maxima.php'; {
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'util/string.php';
require_once QA_INCLUDE_DIR . 'db/maxima.php';
require_once QA_INCLUDE_DIR . 'db/users.php';
if (!strlen($handle)) if (!strlen($handle))
$handle=qa_lang('users/registered_user'); $handle = qa_lang('users/registered_user');
$handle=preg_replace('/[\\@\\+\\/]/', ' ', $handle); $handle = preg_replace('/[\\@\\+\\/]/', ' ', $handle);
for ($attempt=0; $attempt<=99; $attempt++) { for ($attempt = 0; $attempt <= 99; $attempt++) {
$suffix=$attempt ? (' '.$attempt) : ''; $suffix = $attempt ? (' ' . $attempt) : '';
$tryhandle=qa_substr($handle, 0, QA_DB_MAX_HANDLE_LENGTH-strlen($suffix)).$suffix; $tryhandle = qa_substr($handle, 0, QA_DB_MAX_HANDLE_LENGTH - strlen($suffix)) . $suffix;
$filtermodules=qa_load_modules_with('filter', 'filter_handle'); $filtermodules = qa_load_modules_with('filter', 'filter_handle');
foreach ($filtermodules as $filtermodule) foreach ($filtermodules as $filtermodule) {
$filtermodule->filter_handle($tryhandle, null); // filter first without worrying about errors, since our goal is to get a valid one // filter first without worrying about errors, since our goal is to get a valid one
$filtermodule->filter_handle($tryhandle, null);
}
$haderror=false; $haderror = false;
foreach ($filtermodules as $filtermodule) { foreach ($filtermodules as $filtermodule) {
$error=$filtermodule->filter_handle($tryhandle, null); // now check for errors after we've filtered $error = $filtermodule->filter_handle($tryhandle, null); // now check for errors after we've filtered
if (isset($error)) if (isset($error))
$haderror=true; $haderror = true;
} }
if (!$haderror) { if (!$haderror) {
$handleusers=qa_db_user_find_by_handle($tryhandle); $handleusers = qa_db_user_find_by_handle($tryhandle);
if (!count($handleusers)) if (!count($handleusers))
return $tryhandle; return $tryhandle;
} }
} }
qa_fatal_error('Could not create a valid and unique handle from: '.$handle); qa_fatal_error('Could not create a valid and unique handle from: ' . $handle);
} }
function qa_password_validate($password, $olduser=null) /**
/* * Return an array with a single element (key 'password') if user-entered $password is valid, otherwise an empty array.
Return an array with a single element (key 'password') if user-entered $password is valid, otherwise an empty array. * Works by calling through to all filter modules.
Works by calling through to all filter modules. * @param $password
*/ * @param $olduser
{ * @return array
$error=null; */
$filtermodules=qa_load_modules_with('filter', 'validate_password'); function qa_password_validate($password, $olduser = null)
{
$error = null;
$filtermodules = qa_load_modules_with('filter', 'validate_password');
foreach ($filtermodules as $filtermodule) { foreach ($filtermodules as $filtermodule) {
$error=$filtermodule->validate_password($password, $olduser); $error = $filtermodule->validate_password($password, $olduser);
if (isset($error)) if (isset($error))
break; break;
} }
if (!isset($error)) { if (!isset($error)) {
$minpasslen=max(QA_MIN_PASSWORD_LEN, 1); $minpasslen = max(QA_MIN_PASSWORD_LEN, 1);
if (qa_strlen($password)<$minpasslen) if (qa_strlen($password) < $minpasslen)
$error=qa_lang_sub('users/password_min', $minpasslen); $error = qa_lang_sub('users/password_min', $minpasslen);
} }
if (isset($error)) if (isset($error))
return array('password' => $error); return array('password' => $error);
return array(); return array();
} }
function qa_create_new_user($email, $password, $handle, $level=QA_USER_LEVEL_BASIC, $confirmed=false) /**
/* * Create a new user (application level) with $email, $password, $handle and $level.
Create a new user (application level) with $email, $password, $handle and $level. * Set $confirmed to true if the email address has been confirmed elsewhere.
Set $confirmed to true if the email address has been confirmed elsewhere. * Handles user points, notification and optional email confirmation.
Handles user points, notification and optional email confirmation. * @param $email
*/ * @param $password
{ * @param $handle
* @param int $level
* @param bool $confirmed
* @return mixed
*/
function qa_create_new_user($email, $password, $handle, $level = QA_USER_LEVEL_BASIC, $confirmed = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR.'db/points.php'; require_once QA_INCLUDE_DIR . 'db/points.php';
require_once QA_INCLUDE_DIR.'app/options.php'; require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR.'app/emails.php'; require_once QA_INCLUDE_DIR . 'app/emails.php';
require_once QA_INCLUDE_DIR.'app/cookies.php'; require_once QA_INCLUDE_DIR . 'app/cookies.php';
$userid=qa_db_user_create($email, $password, $handle, $level, qa_remote_ip_address()); $userid = qa_db_user_create($email, $password, $handle, $level, qa_remote_ip_address());
qa_db_points_update_ifuser($userid, null); qa_db_points_update_ifuser($userid, null);
qa_db_uapprovecount_update(); qa_db_uapprovecount_update();
...@@ -174,26 +191,26 @@ ...@@ -174,26 +191,26 @@
if (qa_opt('show_notice_welcome')) if (qa_opt('show_notice_welcome'))
qa_db_user_set_flag($userid, QA_USER_FLAGS_WELCOME_NOTICE, true); qa_db_user_set_flag($userid, QA_USER_FLAGS_WELCOME_NOTICE, true);
$custom=qa_opt('show_custom_welcome') ? trim(qa_opt('custom_welcome')) : ''; $custom = qa_opt('show_custom_welcome') ? trim(qa_opt('custom_welcome')) : '';
if (qa_opt('confirm_user_emails') && ($level<QA_USER_LEVEL_EXPERT) && !$confirmed) { if (qa_opt('confirm_user_emails') && $level < QA_USER_LEVEL_EXPERT && !$confirmed) {
$confirm=strtr(qa_lang('emails/welcome_confirm'), array( $confirm = strtr(qa_lang('emails/welcome_confirm'), array(
'^url' => qa_get_new_confirm_url($userid, $handle) '^url' => qa_get_new_confirm_url($userid, $handle),
)); ));
if (qa_opt('confirm_user_required')) if (qa_opt('confirm_user_required'))
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_CONFIRM, true); qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_CONFIRM, true);
} else } else
$confirm=''; $confirm = '';
if (qa_opt('moderate_users') && qa_opt('approve_user_required') && ($level<QA_USER_LEVEL_EXPERT)) if (qa_opt('moderate_users') && qa_opt('approve_user_required') && $level < QA_USER_LEVEL_EXPERT)
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, true); qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, true);
qa_send_notification($userid, $email, $handle, qa_lang('emails/welcome_subject'), qa_lang('emails/welcome_body'), array( qa_send_notification($userid, $email, $handle, qa_lang('emails/welcome_subject'), qa_lang('emails/welcome_body'), array(
'^password' => isset($password) ? qa_lang('main/hidden') : qa_lang('users/password_to_set'), // v 1.6.3: no longer email out passwords '^password' => isset($password) ? qa_lang('main/hidden') : qa_lang('users/password_to_set'), // v 1.6.3: no longer email out passwords
'^url' => qa_opt('site_url'), '^url' => qa_opt('site_url'),
'^custom' => strlen($custom) ? ($custom."\n\n") : '', '^custom' => strlen($custom) ? ($custom . "\n\n") : '',
'^confirm' => $confirm, '^confirm' => $confirm,
)); ));
...@@ -203,23 +220,25 @@ ...@@ -203,23 +220,25 @@
)); ));
return $userid; return $userid;
} }
function qa_delete_user($userid) /**
/* * Delete $userid and all their votes and flags. Their posts will become anonymous.
Delete $userid and all their votes and flags. Their posts will become anonymous. * Handles recalculations of votes and flags for posts this user has affected.
Handles recalculations of votes and flags for posts this user has affected. * @param $userid
*/ * @return mixed
{ */
function qa_delete_user($userid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/votes.php'; require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR.'db/post-update.php'; require_once QA_INCLUDE_DIR . 'db/post-update.php';
require_once QA_INCLUDE_DIR.'db/points.php'; require_once QA_INCLUDE_DIR . 'db/points.php';
$postids=qa_db_uservoteflag_user_get($userid); // posts this user has flagged or voted on, whose counts need updating $postids = qa_db_uservoteflag_user_get($userid); // posts this user has flagged or voted on, whose counts need updating
qa_db_user_delete($userid); qa_db_user_delete($userid);
qa_db_uapprovecount_update(); qa_db_uapprovecount_update();
...@@ -230,45 +249,53 @@ ...@@ -230,45 +249,53 @@
qa_db_post_recount_flags($postid); qa_db_post_recount_flags($postid);
} }
$postuserids=qa_db_posts_get_userids($postids); $postuserids = qa_db_posts_get_userids($postids);
foreach ($postuserids as $postuserid) foreach ($postuserids as $postuserid) {
qa_db_points_update_ifuser($postuserid, array('avoteds','qvoteds', 'upvoteds', 'downvoteds')); qa_db_points_update_ifuser($postuserid, array('avoteds', 'qvoteds', 'upvoteds', 'downvoteds'));
} }
}
function qa_send_new_confirm($userid) /**
/* * Set a new email confirmation code for the user and send it out
Set a new email confirmation code for the user and send it out * @param $userid
*/ * @return mixed
{ */
function qa_send_new_confirm($userid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR.'app/emails.php'; require_once QA_INCLUDE_DIR . 'app/emails.php';
$userinfo=qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true)); $userinfo = qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true));
$emailcode = qa_db_user_rand_emailcode(); $emailcode = qa_db_user_rand_emailcode();
if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/confirm_subject'), qa_lang('emails/confirm_body'), array( if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/confirm_subject'), qa_lang('emails/confirm_body'), array(
'^url' => qa_get_new_confirm_url($userid, $userinfo['handle'], $emailcode), '^url' => qa_get_new_confirm_url($userid, $userinfo['handle'], $emailcode),
'^code' => $emailcode, '^code' => $emailcode,
))) ))) {
qa_fatal_error('Could not send email confirmation'); qa_fatal_error('Could not send email confirmation');
} }
}
function qa_get_new_confirm_url($userid, $handle, $emailcode = null) /**
/* * Set a new email confirmation code for the user and return the corresponding link. If the email code is also sent then that value
Set a new email confirmation code for the user and return the corresponding link. If the email code is also sent then that value * is used. Otherwise, a new email code is generated
is used. Otherwise, a new email code is generated * @param $userid
*/ * @param $handle
{ * @param $emailcode
* @return mixed|string
*/
function qa_get_new_confirm_url($userid, $handle, $emailcode = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
if (!isset($emailcode)) { if (!isset($emailcode)) {
$emailcode = qa_db_user_rand_emailcode(); $emailcode = qa_db_user_rand_emailcode();
...@@ -276,18 +303,22 @@ ...@@ -276,18 +303,22 @@
qa_db_user_set($userid, 'emailcode', $emailcode); qa_db_user_set($userid, 'emailcode', $emailcode);
return qa_path_absolute('confirm', array('c' => $emailcode, 'u' => $handle)); return qa_path_absolute('confirm', array('c' => $emailcode, 'u' => $handle));
} }
function qa_complete_confirm($userid, $email, $handle) /**
/* * Complete the email confirmation process for the user
Complete the email confirmation process for the user * @param $userid
*/ * @param $email
{ * @param $handle
* @return mixed
*/
function qa_complete_confirm($userid, $email, $handle)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR.'app/cookies.php'; require_once QA_INCLUDE_DIR . 'app/cookies.php';
qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, true); qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, true);
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_CONFIRM, false); qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_CONFIRM, false);
...@@ -296,21 +327,25 @@ ...@@ -296,21 +327,25 @@
qa_report_event('u_confirmed', $userid, $handle, qa_cookie_get(), array( qa_report_event('u_confirmed', $userid, $handle, qa_cookie_get(), array(
'email' => $email, 'email' => $email,
)); ));
} }
function qa_set_user_level($userid, $handle, $level, $oldlevel) /**
/* * Set the user level of user $userid with $handle to $level (one of the QA_USER_LEVEL_* constraints in qa-app-users.php)
Set the user level of user $userid with $handle to $level (one of the QA_USER_LEVEL_* constraints in qa-app-users.php) * Pass the previous user level in $oldlevel. Reports the appropriate event, assumes change performed by the logged in user.
Pass the previous user level in $oldlevel. Reports the appropriate event, assumes change performed by the logged in user. * @param $userid
*/ * @param $handle
{ * @param $level
require_once QA_INCLUDE_DIR.'db/users.php'; * @param $oldlevel
*/
function qa_set_user_level($userid, $handle, $level, $oldlevel)
{
require_once QA_INCLUDE_DIR . 'db/users.php';
qa_db_user_set($userid, 'level', $level); qa_db_user_set($userid, 'level', $level);
qa_db_uapprovecount_update(); qa_db_uapprovecount_update();
if ($level>=QA_USER_LEVEL_APPROVED) if ($level >= QA_USER_LEVEL_APPROVED)
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, false); qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, false);
qa_report_event('u_level', qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), array( qa_report_event('u_level', qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), array(
...@@ -319,16 +354,19 @@ ...@@ -319,16 +354,19 @@
'level' => $level, 'level' => $level,
'oldlevel' => $oldlevel, 'oldlevel' => $oldlevel,
)); ));
} }
function qa_set_user_blocked($userid, $handle, $blocked) /**
/* * Set the status of user $userid with $handle to blocked if $blocked is true, otherwise to unblocked. Reports the appropriate
Set the status of user $userid with $handle to blocked if $blocked is true, otherwise to unblocked. Reports the appropriate * event, assumes change performed by the logged in user.
event, assumes change performed by the logged in user. * @param $userid
*/ * @param $handle
{ * @param $blocked
require_once QA_INCLUDE_DIR.'db/users.php'; */
function qa_set_user_blocked($userid, $handle, $blocked)
{
require_once QA_INCLUDE_DIR . 'db/users.php';
qa_db_user_set_flag($userid, QA_USER_FLAGS_USER_BLOCKED, $blocked); qa_db_user_set_flag($userid, QA_USER_FLAGS_USER_BLOCKED, $blocked);
qa_db_uapprovecount_update(); qa_db_uapprovecount_update();
...@@ -337,57 +375,63 @@ ...@@ -337,57 +375,63 @@
'userid' => $userid, 'userid' => $userid,
'handle' => $handle, 'handle' => $handle,
)); ));
} }
function qa_start_reset_user($userid) /**
/* * Start the 'I forgot my password' process for $userid, sending reset code
Start the 'I forgot my password' process for $userid, sending reset code * @param $userid
*/ * @return mixed
{ */
function qa_start_reset_user($userid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR.'app/options.php'; require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR.'app/emails.php'; require_once QA_INCLUDE_DIR . 'app/emails.php';
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
qa_db_user_set($userid, 'emailcode', qa_db_user_rand_emailcode()); qa_db_user_set($userid, 'emailcode', qa_db_user_rand_emailcode());
$userinfo=qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true)); $userinfo = qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true));
if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/reset_subject'), qa_lang('emails/reset_body'), array( if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/reset_subject'), qa_lang('emails/reset_body'), array(
'^code' => $userinfo['emailcode'], '^code' => $userinfo['emailcode'],
'^url' => qa_path_absolute('reset', array('c' => $userinfo['emailcode'], 'e' => $userinfo['email'])), '^url' => qa_path_absolute('reset', array('c' => $userinfo['emailcode'], 'e' => $userinfo['email'])),
))) ))) {
qa_fatal_error('Could not send reset password email'); qa_fatal_error('Could not send reset password email');
} }
}
/** /**
* Successfully finish the 'I forgot my password' process for $userid, sending new password * Successfully finish the 'I forgot my password' process for $userid, sending new password
* *
* @deprecated This function has been replaced by qa_finish_reset_user since Q2A 1.8 * @deprecated This function has been replaced by qa_finish_reset_user since Q2A 1.8
* @param $userid
* @return mixed
*/ */
function qa_complete_reset_user($userid) function qa_complete_reset_user($userid)
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'util/string.php'; require_once QA_INCLUDE_DIR . 'util/string.php';
require_once QA_INCLUDE_DIR.'app/options.php'; require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR.'app/emails.php'; require_once QA_INCLUDE_DIR . 'app/emails.php';
require_once QA_INCLUDE_DIR.'app/cookies.php'; require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
$password=qa_random_alphanum(max(QA_MIN_PASSWORD_LEN, QA_NEW_PASSWORD_LEN)); $password = qa_random_alphanum(max(QA_MIN_PASSWORD_LEN, QA_NEW_PASSWORD_LEN));
$userinfo=qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true)); $userinfo = qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true));
if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/new_password_subject'), qa_lang('emails/new_password_body'), array( if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/new_password_subject'), qa_lang('emails/new_password_body'), array(
'^password' => $password, '^password' => $password,
'^url' => qa_opt('site_url'), '^url' => qa_opt('site_url'),
))) ))) {
qa_fatal_error('Could not send new password - password not reset'); qa_fatal_error('Could not send new password - password not reset');
}
qa_db_user_set_password($userid, $password); // do this last, to be safe qa_db_user_set_password($userid, $password); // do this last, to be safe
qa_db_user_set($userid, 'emailcode', ''); // so can't be reused qa_db_user_set($userid, 'emailcode', ''); // so can't be reused
...@@ -395,7 +439,7 @@ ...@@ -395,7 +439,7 @@
qa_report_event('u_reset', $userid, $userinfo['handle'], qa_cookie_get(), array( qa_report_event('u_reset', $userid, $userinfo['handle'], qa_cookie_get(), array(
'email' => $userinfo['email'], 'email' => $userinfo['email'],
)); ));
} }
/** /**
...@@ -404,8 +448,8 @@ ...@@ -404,8 +448,8 @@
* @param string $newPassword The new password for the user * @param string $newPassword The new password for the user
* @return void * @return void
*/ */
function qa_finish_reset_user($userId, $newPassword) function qa_finish_reset_user($userId, $newPassword)
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// For qa_db_user_set_password(), qa_db_user_set() // For qa_db_user_set_password(), qa_db_user_set()
...@@ -434,34 +478,38 @@ ...@@ -434,34 +478,38 @@
qa_report_event('u_reset', $userId, $userInfo['handle'], qa_cookie_get(), array( qa_report_event('u_reset', $userId, $userInfo['handle'], qa_cookie_get(), array(
'email' => $userInfo['email'], 'email' => $userInfo['email'],
)); ));
} }
function qa_logged_in_user_flush() /**
/* * Flush any information about the currently logged in user, so it is retrieved from database again
Flush any information about the currently logged in user, so it is retrieved from database again */
*/ function qa_logged_in_user_flush()
{ {
global $qa_cached_logged_in_user; global $qa_cached_logged_in_user;
$qa_cached_logged_in_user=null; $qa_cached_logged_in_user = null;
} }
function qa_set_user_avatar($userid, $imagedata, $oldblobid=null) /**
/* * Set the avatar of $userid to the image in $imagedata, and remove $oldblobid from the database if not null
Set the avatar of $userid to the image in $imagedata, and remove $oldblobid from the database if not null * @param $userid
*/ * @param $imagedata
{ * @param $oldblobid
* @return bool
*/
function qa_set_user_avatar($userid, $imagedata, $oldblobid = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'util/image.php'; require_once QA_INCLUDE_DIR . 'util/image.php';
$imagedata=qa_image_constrain_data($imagedata, $width, $height, qa_opt('avatar_store_size')); $imagedata = qa_image_constrain_data($imagedata, $width, $height, qa_opt('avatar_store_size'));
if (isset($imagedata)) { if (isset($imagedata)) {
require_once QA_INCLUDE_DIR.'app/blobs.php'; require_once QA_INCLUDE_DIR . 'app/blobs.php';
$newblobid=qa_create_blob($imagedata, 'jpeg', null, $userid, null, qa_remote_ip_address()); $newblobid = qa_create_blob($imagedata, 'jpeg', null, $userid, null, qa_remote_ip_address());
if (isset($newblobid)) { if (isset($newblobid)) {
qa_db_user_set($userid, 'avatarblobid', $newblobid); qa_db_user_set($userid, 'avatarblobid', $newblobid);
...@@ -478,9 +526,4 @@ ...@@ -478,9 +526,4 @@
} }
return false; return false;
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,37 +20,42 @@ ...@@ -20,37 +20,42 @@
More about this license: http://www.question2answer.org/license.php 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 if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
function qa_vote_error_html($post, $vote, $userid, $topage) /**
/* * Check if $userid can vote on $post, on the page $topage.
Check if $userid can vote on $post, on the page $topage. * Return an HTML error to display if there was a problem, or false if it's OK.
Return an HTML error to display if there was a problem, or false if it's OK. * @param $post
*/ * @param $vote
{ * @param $userid
* @param $topage
* @return bool|mixed|string
*/
function qa_vote_error_html($post, $vote, $userid, $topage)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// The 'login', 'confirm', 'limit', 'userblock' and 'ipblock' permission errors are reported to the user here. // The 'login', 'confirm', 'limit', 'userblock' and 'ipblock' permission errors are reported to the user here.
// Others ('approve', 'level') prevent the buttons being clickable in the first place, in qa_get_vote_view(...) // Others ('approve', 'level') prevent the buttons being clickable in the first place, in qa_get_vote_view(...)
require_once QA_INCLUDE_DIR.'app/users.php'; require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR.'app/limits.php'; require_once QA_INCLUDE_DIR . 'app/limits.php';
if ( if (
is_array($post) && is_array($post) &&
( ($post['basetype']=='Q') || ($post['basetype']=='A') ) && ($post['basetype'] == 'Q' || $post['basetype'] == 'A') &&
qa_opt(($post['basetype']=='Q') ? 'voting_on_qs' : 'voting_on_as') && qa_opt(($post['basetype'] == 'Q') ? 'voting_on_qs' : 'voting_on_as') &&
( (!isset($post['userid'])) || (!isset($userid)) || ($post['userid']!=$userid) ) (!isset($post['userid']) || !isset($userid) || $post['userid'] != $userid)
) { ) {
$permiterror=qa_user_post_permit_error(($post['basetype']=='Q') ? 'permit_vote_q' : 'permit_vote_a', $post, QA_LIMIT_VOTES); $permiterror = qa_user_post_permit_error(($post['basetype'] == 'Q') ? 'permit_vote_q' : 'permit_vote_a', $post, QA_LIMIT_VOTES);
$errordownonly=(!$permiterror) && ($vote<0); $errordownonly = !$permiterror && $vote < 0;
if ($errordownonly) if ($errordownonly)
$permiterror=qa_user_post_permit_error('permit_vote_down', $post); $permiterror = qa_user_post_permit_error('permit_vote_down', $post);
switch ($permiterror) { switch ($permiterror) {
case 'login': case 'login':
...@@ -75,57 +80,63 @@ ...@@ -75,57 +80,63 @@
} else } else
return qa_lang_html('main/vote_not_allowed'); // voting option should not have been presented (but could happen due to options change) return qa_lang_html('main/vote_not_allowed'); // voting option should not have been presented (but could happen due to options change)
} }
function qa_vote_set($post, $userid, $handle, $cookieid, $vote) /**
/* * Actually set (application level) the $vote (-1/0/1) by $userid (with $handle and $cookieid) on $postid.
Actually set (application level) the $vote (-1/0/1) by $userid (with $handle and $cookieid) on $postid. * Handles user points, recounting and event reports as appropriate.
Handles user points, recounting and event reports as appropriate. * @param $post
*/ * @param $userid
{ * @param $handle
* @param $cookieid
* @param $vote
* @return mixed
*/
function qa_vote_set($post, $userid, $handle, $cookieid, $vote)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/points.php'; require_once QA_INCLUDE_DIR . 'db/points.php';
require_once QA_INCLUDE_DIR.'db/hotness.php'; require_once QA_INCLUDE_DIR . 'db/hotness.php';
require_once QA_INCLUDE_DIR.'db/votes.php'; require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR.'db/post-create.php'; require_once QA_INCLUDE_DIR . 'db/post-create.php';
require_once QA_INCLUDE_DIR.'app/limits.php'; require_once QA_INCLUDE_DIR . 'app/limits.php';
$vote=(int)min(1, max(-1, $vote)); $vote = (int)min(1, max(-1, $vote));
$oldvote=(int)qa_db_uservote_get($post['postid'], $userid); $oldvote = (int)qa_db_uservote_get($post['postid'], $userid);
qa_db_uservote_set($post['postid'], $userid, $vote); qa_db_uservote_set($post['postid'], $userid, $vote);
qa_db_post_recount_votes($post['postid']); qa_db_post_recount_votes($post['postid']);
$postisanswer=($post['basetype']=='A'); $postisanswer = ($post['basetype'] == 'A');
if ($postisanswer) { if ($postisanswer) {
qa_db_post_acount_update($post['parentid']); qa_db_post_acount_update($post['parentid']);
qa_db_unupaqcount_update(); qa_db_unupaqcount_update();
} }
$columns=array(); $columns = array();
if ( ($vote>0) || ($oldvote>0) ) if ($vote > 0 || $oldvote > 0)
$columns[]=$postisanswer ? 'aupvotes' : 'qupvotes'; $columns[] = $postisanswer ? 'aupvotes' : 'qupvotes';
if ( ($vote<0) || ($oldvote<0) ) if ($vote < 0 || $oldvote < 0)
$columns[]=$postisanswer ? 'adownvotes' : 'qdownvotes'; $columns[] = $postisanswer ? 'adownvotes' : 'qdownvotes';
qa_db_points_update_ifuser($userid, $columns); qa_db_points_update_ifuser($userid, $columns);
qa_db_points_update_ifuser($post['userid'], array($postisanswer ? 'avoteds' : 'qvoteds', 'upvoteds', 'downvoteds')); qa_db_points_update_ifuser($post['userid'], array($postisanswer ? 'avoteds' : 'qvoteds', 'upvoteds', 'downvoteds'));
if ($post['basetype']=='Q') if ($post['basetype'] == 'Q')
qa_db_hotness_update($post['postid']); qa_db_hotness_update($post['postid']);
if ($vote<0) if ($vote < 0)
$event=$postisanswer ? 'a_vote_down' : 'q_vote_down'; $event = $postisanswer ? 'a_vote_down' : 'q_vote_down';
elseif ($vote>0) elseif ($vote > 0)
$event=$postisanswer ? 'a_vote_up' : 'q_vote_up'; $event = $postisanswer ? 'a_vote_up' : 'q_vote_up';
else else
$event=$postisanswer ? 'a_vote_nil' : 'q_vote_nil'; $event = $postisanswer ? 'a_vote_nil' : 'q_vote_nil';
qa_report_event($event, $userid, $handle, $cookieid, array( qa_report_event($event, $userid, $handle, $cookieid, array(
'postid' => $post['postid'], 'postid' => $post['postid'],
...@@ -133,29 +144,33 @@ ...@@ -133,29 +144,33 @@
'vote' => $vote, 'vote' => $vote,
'oldvote' => $oldvote, 'oldvote' => $oldvote,
)); ));
} }
function qa_flag_error_html($post, $userid, $topage) /**
/* * Check if $userid can flag $post, on the page $topage.
Check if $userid can flag $post, on the page $topage. * Return an HTML error to display if there was a problem, or false if it's OK.
Return an HTML error to display if there was a problem, or false if it's OK. * @param $post
*/ * @param $userid
{ * @param $topage
* @return bool|mixed|string
*/
function qa_flag_error_html($post, $userid, $topage)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// The 'login', 'confirm', 'limit', 'userblock' and 'ipblock' permission errors are reported to the user here. // The 'login', 'confirm', 'limit', 'userblock' and 'ipblock' permission errors are reported to the user here.
// Others ('approve', 'level') prevent the flag button being shown, in qa_page_q_post_rules(...) // Others ('approve', 'level') prevent the flag button being shown, in qa_page_q_post_rules(...)
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR.'app/options.php'; require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR.'app/users.php'; require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR.'app/limits.php'; require_once QA_INCLUDE_DIR . 'app/limits.php';
if ( if (
is_array($post) && is_array($post) &&
qa_opt('flagging_of_posts') && qa_opt('flagging_of_posts') &&
( (!isset($post['userid'])) || (!isset($userid)) || ($post['userid']!=$userid) ) (!isset($post['userid']) || !isset($userid) || $post['userid'] != $userid)
) { ) {
switch (qa_user_post_permit_error('permit_flag', $post, QA_LIMIT_FLAGS)) { switch (qa_user_post_permit_error('permit_flag', $post, QA_LIMIT_FLAGS)) {
...@@ -181,21 +196,27 @@ ...@@ -181,21 +196,27 @@
} else } else
return qa_lang_html('question/flag_not_allowed'); // flagging option should not have been presented return qa_lang_html('question/flag_not_allowed'); // flagging option should not have been presented
} }
function qa_flag_set_tohide($oldpost, $userid, $handle, $cookieid, $question) /**
/* * Set (application level) a flag by $userid (with $handle and $cookieid) on $oldpost which belongs to $question.
Set (application level) a flag by $userid (with $handle and $cookieid) on $oldpost which belongs to $question. * Handles recounting, admin notifications and event reports as appropriate.
Handles recounting, admin notifications and event reports as appropriate. * Returns true if the post should now be hidden because it has accumulated enough flags.
Returns true if the post should now be hidden because it has accumulated enough flags. * @param $oldpost
*/ * @param $userid
{ * @param $handle
* @param $cookieid
* @param $question
* @return bool
*/
function qa_flag_set_tohide($oldpost, $userid, $handle, $cookieid, $question)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/votes.php'; require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR.'app/limits.php'; require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR.'db/post-update.php'; require_once QA_INCLUDE_DIR . 'db/post-update.php';
qa_db_userflag_set($oldpost['postid'], $userid, true); qa_db_userflag_set($oldpost['postid'], $userid, true);
qa_db_post_recount_flags($oldpost['postid']); qa_db_post_recount_flags($oldpost['postid']);
...@@ -203,19 +224,19 @@ ...@@ -203,19 +224,19 @@
switch ($oldpost['basetype']) { switch ($oldpost['basetype']) {
case 'Q': case 'Q':
$event='q_flag'; $event = 'q_flag';
break; break;
case 'A': case 'A':
$event='a_flag'; $event = 'a_flag';
break; break;
case 'C': case 'C':
$event='c_flag'; $event = 'c_flag';
break; break;
} }
$post=qa_db_select_with_pending(qa_db_full_post_selectspec(null, $oldpost['postid'])); $post = qa_db_select_with_pending(qa_db_full_post_selectspec(null, $oldpost['postid']));
qa_report_event($event, $userid, $handle, $cookieid, array( qa_report_event($event, $userid, $handle, $cookieid, array(
'postid' => $oldpost['postid'], 'postid' => $oldpost['postid'],
...@@ -225,21 +246,26 @@ ...@@ -225,21 +246,26 @@
'question' => $question, 'question' => $question,
)); ));
return ($post['flagcount']>=qa_opt('flagging_hide_after')) && !$post['hidden']; return $post['flagcount'] >= qa_opt('flagging_hide_after') && !$post['hidden'];
} }
function qa_flag_clear($oldpost, $userid, $handle, $cookieid) /**
/* * Clear (application level) a flag on $oldpost by $userid (with $handle and $cookieid).
Clear (application level) a flag on $oldpost by $userid (with $handle and $cookieid). * Handles recounting and event reports as appropriate.
Handles recounting and event reports as appropriate. * @param $oldpost
*/ * @param $userid
{ * @param $handle
* @param $cookieid
* @return mixed
*/
function qa_flag_clear($oldpost, $userid, $handle, $cookieid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/votes.php'; require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR.'app/limits.php'; require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR.'db/post-update.php'; require_once QA_INCLUDE_DIR . 'db/post-update.php';
qa_db_userflag_set($oldpost['postid'], $userid, false); qa_db_userflag_set($oldpost['postid'], $userid, false);
qa_db_post_recount_flags($oldpost['postid']); qa_db_post_recount_flags($oldpost['postid']);
...@@ -247,15 +273,15 @@ ...@@ -247,15 +273,15 @@
switch ($oldpost['basetype']) { switch ($oldpost['basetype']) {
case 'Q': case 'Q':
$event='q_unflag'; $event = 'q_unflag';
break; break;
case 'A': case 'A':
$event='a_unflag'; $event = 'a_unflag';
break; break;
case 'C': case 'C':
$event='c_unflag'; $event = 'c_unflag';
break; break;
} }
...@@ -263,20 +289,25 @@ ...@@ -263,20 +289,25 @@
'postid' => $oldpost['postid'], 'postid' => $oldpost['postid'],
'oldpost' => $oldpost, 'oldpost' => $oldpost,
)); ));
} }
function qa_flags_clear_all($oldpost, $userid, $handle, $cookieid) /**
/* * Clear (application level) all flags on $oldpost by $userid (with $handle and $cookieid).
Clear (application level) all flags on $oldpost by $userid (with $handle and $cookieid). * Handles recounting and event reports as appropriate.
Handles recounting and event reports as appropriate. * @param $oldpost
*/ * @param $userid
{ * @param $handle
* @param $cookieid
* @return mixed
*/
function qa_flags_clear_all($oldpost, $userid, $handle, $cookieid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/votes.php'; require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR.'app/limits.php'; require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR.'db/post-update.php'; require_once QA_INCLUDE_DIR . 'db/post-update.php';
qa_db_userflags_clear_all($oldpost['postid']); qa_db_userflags_clear_all($oldpost['postid']);
qa_db_post_recount_flags($oldpost['postid']); qa_db_post_recount_flags($oldpost['postid']);
...@@ -284,15 +315,15 @@ ...@@ -284,15 +315,15 @@
switch ($oldpost['basetype']) { switch ($oldpost['basetype']) {
case 'Q': case 'Q':
$event='q_clearflags'; $event = 'q_clearflags';
break; break;
case 'A': case 'A':
$event='a_clearflags'; $event = 'a_clearflags';
break; break;
case 'C': case 'C':
$event='c_clearflags'; $event = 'c_clearflags';
break; break;
} }
...@@ -300,9 +331,4 @@ ...@@ -300,9 +331,4 @@
'postid' => $oldpost['postid'], 'postid' => $oldpost['postid'],
'oldpost' => $oldpost, 'oldpost' => $oldpost,
)); ));
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
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