inital commit
This commit is contained in:
252
webroot/forum/inc/3rdparty/2fa/GoogleAuthenticator.php
vendored
Normal file
252
webroot/forum/inc/3rdparty/2fa/GoogleAuthenticator.php
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Class for handling Google Authenticator 2-factor authentication.
|
||||
*
|
||||
* @author Michael Kliewe
|
||||
* @copyright 2012 Michael Kliewe
|
||||
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
|
||||
*
|
||||
* @link http://www.phpgangsta.de/
|
||||
*/
|
||||
class PHPGangsta_GoogleAuthenticator
|
||||
{
|
||||
protected $_codeLength = 6;
|
||||
|
||||
/**
|
||||
* Create new secret.
|
||||
* 16 characters, randomly chosen from the allowed base32 characters.
|
||||
*
|
||||
* @param int $secretLength
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function createSecret($secretLength = 16)
|
||||
{
|
||||
$validChars = $this->_getBase32LookupTable();
|
||||
|
||||
// Valid secret lengths are 80 to 640 bits
|
||||
if ($secretLength < 16 || $secretLength > 128) {
|
||||
throw new Exception('Bad secret length');
|
||||
}
|
||||
$secret = '';
|
||||
$rnd = false;
|
||||
if (function_exists('random_bytes')) {
|
||||
$rnd = random_bytes($secretLength);
|
||||
} elseif (function_exists('mcrypt_create_iv')) {
|
||||
$rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM);
|
||||
} elseif (function_exists('openssl_random_pseudo_bytes')) {
|
||||
$rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
|
||||
if (!$cryptoStrong) {
|
||||
$rnd = false;
|
||||
}
|
||||
}
|
||||
if ($rnd !== false) {
|
||||
for ($i = 0; $i < $secretLength; ++$i) {
|
||||
$secret .= $validChars[ord($rnd[$i]) & 31];
|
||||
}
|
||||
} else {
|
||||
throw new Exception('No source of secure random');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the code, with given secret and point in time.
|
||||
*
|
||||
* @param string $secret
|
||||
* @param int|null $timeSlice
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCode($secret, $timeSlice = null)
|
||||
{
|
||||
if ($timeSlice === null) {
|
||||
$timeSlice = floor(time() / 30);
|
||||
}
|
||||
|
||||
$secretkey = $this->_base32Decode($secret);
|
||||
|
||||
// Pack time into binary string
|
||||
$time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice);
|
||||
// Hash it with users secret key
|
||||
$hm = hash_hmac('SHA1', $time, $secretkey, true);
|
||||
// Use last nipple of result as index/offset
|
||||
$offset = ord(substr($hm, -1)) & 0x0F;
|
||||
// grab 4 bytes of the result
|
||||
$hashpart = substr($hm, $offset, 4);
|
||||
|
||||
// Unpak binary value
|
||||
$value = unpack('N', $hashpart);
|
||||
$value = $value[1];
|
||||
// Only 32 bits
|
||||
$value = $value & 0x7FFFFFFF;
|
||||
|
||||
$modulo = pow(10, $this->_codeLength);
|
||||
|
||||
return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get QR-Code URL for image, from google charts.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $secret
|
||||
* @param string $title
|
||||
* @param array $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array())
|
||||
{
|
||||
$width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
|
||||
$height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
|
||||
$level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
|
||||
|
||||
$urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
|
||||
if (isset($title)) {
|
||||
$urlencoded .= urlencode('&issuer='.urlencode($title));
|
||||
}
|
||||
|
||||
return 'https://chart.googleapis.com/chart?chs='.$width.'x'.$height.'&chld='.$level.'|0&cht=qr&chl='.$urlencoded.'';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now.
|
||||
*
|
||||
* @param string $secret
|
||||
* @param string $code
|
||||
* @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
|
||||
* @param int|null $currentTimeSlice time slice if we want use other that time()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
|
||||
{
|
||||
if ($currentTimeSlice === null) {
|
||||
$currentTimeSlice = floor(time() / 30);
|
||||
}
|
||||
|
||||
if (strlen($code) != 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
|
||||
$calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
|
||||
if ($this->timingSafeEquals($calculatedCode, $code)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the code length, should be >=6.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return PHPGangsta_GoogleAuthenticator
|
||||
*/
|
||||
public function setCodeLength($length)
|
||||
{
|
||||
$this->_codeLength = $length;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to decode base32.
|
||||
*
|
||||
* @param $secret
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function _base32Decode($secret)
|
||||
{
|
||||
if (empty($secret)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$base32chars = $this->_getBase32LookupTable();
|
||||
$base32charsFlipped = array_flip($base32chars);
|
||||
|
||||
$paddingCharCount = substr_count($secret, $base32chars[32]);
|
||||
$allowedValues = array(6, 4, 3, 1, 0);
|
||||
if (!in_array($paddingCharCount, $allowedValues)) {
|
||||
return false;
|
||||
}
|
||||
for ($i = 0; $i < 4; ++$i) {
|
||||
if ($paddingCharCount == $allowedValues[$i] &&
|
||||
substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$secret = str_replace('=', '', $secret);
|
||||
$secret = str_split($secret);
|
||||
$binaryString = '';
|
||||
for ($i = 0; $i < count($secret); $i = $i + 8) {
|
||||
$x = '';
|
||||
if (!in_array($secret[$i], $base32chars)) {
|
||||
return false;
|
||||
}
|
||||
for ($j = 0; $j < 8; ++$j) {
|
||||
$x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
|
||||
}
|
||||
$eightBits = str_split($x, 8);
|
||||
for ($z = 0; $z < count($eightBits); ++$z) {
|
||||
$binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : '';
|
||||
}
|
||||
}
|
||||
|
||||
return $binaryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array with all 32 characters for decoding from/encoding to base32.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _getBase32LookupTable()
|
||||
{
|
||||
return array(
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
|
||||
'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
|
||||
'=', // padding char
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A timing safe equals comparison
|
||||
* more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html.
|
||||
*
|
||||
* @param string $safeString The internal (safe) value to be checked
|
||||
* @param string $userString The user submitted (unsafe) value
|
||||
*
|
||||
* @return bool True if the two strings are identical
|
||||
*/
|
||||
private function timingSafeEquals($safeString, $userString)
|
||||
{
|
||||
if (function_exists('hash_equals')) {
|
||||
return hash_equals($safeString, $userString);
|
||||
}
|
||||
$safeLen = strlen($safeString);
|
||||
$userLen = strlen($userString);
|
||||
|
||||
if ($userLen != $safeLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = 0;
|
||||
|
||||
for ($i = 0; $i < $userLen; ++$i) {
|
||||
$result |= (ord($safeString[$i]) ^ ord($userString[$i]));
|
||||
}
|
||||
|
||||
// They are only identical strings if $result is exactly 0...
|
||||
return $result === 0;
|
||||
}
|
||||
}
|
||||
257
webroot/forum/inc/3rdparty/diff/Diff.php
vendored
Normal file
257
webroot/forum/inc/3rdparty/diff/Diff.php
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
/**
|
||||
* General API for generating and formatting diffs - the differences between
|
||||
* two sequences of strings.
|
||||
*
|
||||
* The original PHP version of this code was written by Geoffrey T. Dairiki
|
||||
* <dairiki@dairiki.org>, and is used/adapted with his permission.
|
||||
*
|
||||
* Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff
|
||||
{
|
||||
/**
|
||||
* Array of changes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_edits;
|
||||
|
||||
/**
|
||||
* Computes diffs between sequences of strings.
|
||||
*
|
||||
* @param string $engine Name of the diffing engine to use. 'auto'
|
||||
* will automatically select the best.
|
||||
* @param array $params Parameters to pass to the diffing engine.
|
||||
* Normally an array of two arrays, each
|
||||
* containing the lines from a file.
|
||||
*/
|
||||
public function __construct($engine, $params)
|
||||
{
|
||||
if ($engine == 'auto') {
|
||||
$engine = extension_loaded('xdiff') ? 'Xdiff' : 'Native';
|
||||
} else {
|
||||
$engine = Horde_String::ucfirst(basename($engine));
|
||||
}
|
||||
|
||||
// Fugly; Include operational classes required for Text_Diff
|
||||
$classes = array(
|
||||
'String.php',
|
||||
"Engine/{$engine}.php",
|
||||
'Renderer/Inline.php',
|
||||
'Op/Base.php',
|
||||
'Op/Copy.php',
|
||||
'Op/Change.php',
|
||||
'Op/Add.php',
|
||||
'Op/Delete.php'
|
||||
);
|
||||
|
||||
foreach($classes as $class)
|
||||
{
|
||||
require_once MYBB_ROOT."inc/3rdparty/diff/Diff/{$class}";
|
||||
}
|
||||
|
||||
$class = 'Horde_Text_Diff_Engine_' . $engine;
|
||||
$diff_engine = new $class();
|
||||
|
||||
$this->_edits = call_user_func_array(array($diff_engine, 'diff'), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of differences.
|
||||
*/
|
||||
public function getDiff()
|
||||
{
|
||||
return $this->_edits;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of new (added) lines in a given diff.
|
||||
*
|
||||
* @return integer The number of new lines
|
||||
*/
|
||||
public function countAddedLines()
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit instanceof Horde_Text_Diff_Op_Add ||
|
||||
$edit instanceof Horde_Text_Diff_Op_Change) {
|
||||
$count += $edit->nfinal();
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of deleted (removed) lines in a given diff.
|
||||
*
|
||||
* @return integer The number of deleted lines
|
||||
*/
|
||||
public function countDeletedLines()
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit instanceof Horde_Text_Diff_Op_Delete ||
|
||||
$edit instanceof Horde_Text_Diff_Op_Change) {
|
||||
$count += $edit->norig();
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a reversed diff.
|
||||
*
|
||||
* Example:
|
||||
* <code>
|
||||
* $diff = new Horde_Text_Diff($lines1, $lines2);
|
||||
* $rev = $diff->reverse();
|
||||
* </code>
|
||||
*
|
||||
* @return Horde_Text_Diff A Diff object representing the inverse of the
|
||||
* original diff. Note that we purposely don't return a
|
||||
* reference here, since this essentially is a clone()
|
||||
* method.
|
||||
*/
|
||||
public function reverse()
|
||||
{
|
||||
if (version_compare(zend_version(), '2', '>')) {
|
||||
$rev = clone($this);
|
||||
} else {
|
||||
$rev = $this;
|
||||
}
|
||||
$rev->_edits = array();
|
||||
foreach ($this->_edits as $edit) {
|
||||
$rev->_edits[] = $edit->reverse();
|
||||
}
|
||||
return $rev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for an empty diff.
|
||||
*
|
||||
* @return boolean True if two sequences were identical.
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
foreach ($this->_edits as $edit) {
|
||||
if (!($edit instanceof Horde_Text_Diff_Op_Copy)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the length of the Longest Common Subsequence (LCS).
|
||||
*
|
||||
* This is mostly for diagnostic purposes.
|
||||
*
|
||||
* @return integer The length of the LCS.
|
||||
*/
|
||||
public function lcs()
|
||||
{
|
||||
$lcs = 0;
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit instanceof Horde_Text_Diff_Op_Copy) {
|
||||
$lcs += count($edit->orig);
|
||||
}
|
||||
}
|
||||
return $lcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original set of lines.
|
||||
*
|
||||
* This reconstructs the $from_lines parameter passed to the constructor.
|
||||
*
|
||||
* @return array The original sequence of strings.
|
||||
*/
|
||||
public function getOriginal()
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit->orig) {
|
||||
array_splice($lines, count($lines), 0, $edit->orig);
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the final set of lines.
|
||||
*
|
||||
* This reconstructs the $to_lines parameter passed to the constructor.
|
||||
*
|
||||
* @return array The sequence of strings.
|
||||
*/
|
||||
public function getFinal()
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit->final) {
|
||||
array_splice($lines, count($lines), 0, $edit->final);
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes trailing newlines from a line of text. This is meant to be used
|
||||
* with array_walk().
|
||||
*
|
||||
* @param string $line The line to trim.
|
||||
* @param integer $key The index of the line in the array. Not used.
|
||||
*/
|
||||
public static function trimNewlines(&$line, $key)
|
||||
{
|
||||
$line = str_replace(array("\n", "\r"), '', $line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a diff for validity.
|
||||
*
|
||||
* This is here only for debugging purposes.
|
||||
*/
|
||||
protected function _check($from_lines, $to_lines)
|
||||
{
|
||||
if (serialize($from_lines) != serialize($this->getOriginal())) {
|
||||
trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
|
||||
}
|
||||
if (serialize($to_lines) != serialize($this->getFinal())) {
|
||||
trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
|
||||
}
|
||||
|
||||
$rev = $this->reverse();
|
||||
if (serialize($to_lines) != serialize($rev->getOriginal())) {
|
||||
trigger_error("Reversed original doesn't match", E_USER_ERROR);
|
||||
}
|
||||
if (serialize($from_lines) != serialize($rev->getFinal())) {
|
||||
trigger_error("Reversed final doesn't match", E_USER_ERROR);
|
||||
}
|
||||
|
||||
$prevtype = null;
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($prevtype == get_class($edit)) {
|
||||
trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
|
||||
}
|
||||
$prevtype = get_class($edit);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
444
webroot/forum/inc/3rdparty/diff/Diff/Engine/Native.php
vendored
Normal file
444
webroot/forum/inc/3rdparty/diff/Diff/Engine/Native.php
vendored
Normal file
@@ -0,0 +1,444 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used internally by Horde_Text_Diff to actually compute the diffs.
|
||||
*
|
||||
* This class is implemented using native PHP code.
|
||||
*
|
||||
* The algorithm used here is mostly lifted from the perl module
|
||||
* Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
|
||||
* http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
|
||||
*
|
||||
* More ideas are taken from: http://www.ics.uci.edu/~eppstein/161/960229.html
|
||||
*
|
||||
* Some ideas (and a bit of code) are taken from analyze.c, of GNU
|
||||
* diffutils-2.7, which can be found at:
|
||||
* ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
|
||||
*
|
||||
* Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from
|
||||
* Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this
|
||||
* code was written by him, and is used/adapted with his permission.
|
||||
*
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file LICENSE for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Engine_Native
|
||||
{
|
||||
public function diff($from_lines, $to_lines)
|
||||
{
|
||||
array_walk($from_lines, array('Horde_Text_Diff', 'trimNewlines'));
|
||||
array_walk($to_lines, array('Horde_Text_Diff', 'trimNewlines'));
|
||||
|
||||
$n_from = count($from_lines);
|
||||
$n_to = count($to_lines);
|
||||
|
||||
$this->xchanged = $this->ychanged = array();
|
||||
$this->xv = $this->yv = array();
|
||||
$this->xind = $this->yind = array();
|
||||
unset($this->seq);
|
||||
unset($this->in_seq);
|
||||
unset($this->lcs);
|
||||
|
||||
// Skip leading common lines.
|
||||
for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
|
||||
if ($from_lines[$skip] !== $to_lines[$skip]) {
|
||||
break;
|
||||
}
|
||||
$this->xchanged[$skip] = $this->ychanged[$skip] = false;
|
||||
}
|
||||
|
||||
// Skip trailing common lines.
|
||||
$xi = $n_from; $yi = $n_to;
|
||||
for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
|
||||
if ($from_lines[$xi] !== $to_lines[$yi]) {
|
||||
break;
|
||||
}
|
||||
$this->xchanged[$xi] = $this->ychanged[$yi] = false;
|
||||
}
|
||||
|
||||
// Ignore lines which do not exist in both files.
|
||||
for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
|
||||
$xhash[$from_lines[$xi]] = 1;
|
||||
}
|
||||
for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
|
||||
$line = $to_lines[$yi];
|
||||
if (($this->ychanged[$yi] = empty($xhash[$line]))) {
|
||||
continue;
|
||||
}
|
||||
$yhash[$line] = 1;
|
||||
$this->yv[] = $line;
|
||||
$this->yind[] = $yi;
|
||||
}
|
||||
for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
|
||||
$line = $from_lines[$xi];
|
||||
if (($this->xchanged[$xi] = empty($yhash[$line]))) {
|
||||
continue;
|
||||
}
|
||||
$this->xv[] = $line;
|
||||
$this->xind[] = $xi;
|
||||
}
|
||||
|
||||
// Find the LCS.
|
||||
$this->_compareseq(0, count($this->xv), 0, count($this->yv));
|
||||
|
||||
// Merge edits when possible.
|
||||
$this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged);
|
||||
$this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged);
|
||||
|
||||
// Compute the edit operations.
|
||||
$edits = array();
|
||||
$xi = $yi = 0;
|
||||
while ($xi < $n_from || $yi < $n_to) {
|
||||
assert($yi < $n_to || $this->xchanged[$xi]);
|
||||
assert($xi < $n_from || $this->ychanged[$yi]);
|
||||
|
||||
// Skip matching "snake".
|
||||
$copy = array();
|
||||
while ($xi < $n_from && $yi < $n_to
|
||||
&& !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
|
||||
$copy[] = $from_lines[$xi++];
|
||||
++$yi;
|
||||
}
|
||||
if ($copy) {
|
||||
$edits[] = new Horde_Text_Diff_Op_Copy($copy);
|
||||
}
|
||||
|
||||
// Find deletes & adds.
|
||||
$delete = array();
|
||||
while ($xi < $n_from && $this->xchanged[$xi]) {
|
||||
$delete[] = $from_lines[$xi++];
|
||||
}
|
||||
|
||||
$add = array();
|
||||
while ($yi < $n_to && $this->ychanged[$yi]) {
|
||||
$add[] = $to_lines[$yi++];
|
||||
}
|
||||
|
||||
if ($delete && $add) {
|
||||
$edits[] = new Horde_Text_Diff_Op_Change($delete, $add);
|
||||
} elseif ($delete) {
|
||||
$edits[] = new Horde_Text_Diff_Op_Delete($delete);
|
||||
} elseif ($add) {
|
||||
$edits[] = new Horde_Text_Diff_Op_Add($add);
|
||||
}
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
|
||||
* XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized
|
||||
* segments.
|
||||
*
|
||||
* Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of
|
||||
* NCHUNKS+1 (X, Y) indexes giving the diving points between sub
|
||||
* sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1),
|
||||
* the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) ==
|
||||
* (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
|
||||
*
|
||||
* This public function assumes that the first lines of the specified portions of
|
||||
* the two files do not match, and likewise that the last lines do not
|
||||
* match. The caller must trim matching lines from the beginning and end
|
||||
* of the portions it is going to specify.
|
||||
*/
|
||||
protected function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks)
|
||||
{
|
||||
$flip = false;
|
||||
|
||||
if ($xlim - $xoff > $ylim - $yoff) {
|
||||
/* Things seems faster (I'm not sure I understand why) when the
|
||||
* shortest sequence is in X. */
|
||||
$flip = true;
|
||||
list ($xoff, $xlim, $yoff, $ylim)
|
||||
= array($yoff, $ylim, $xoff, $xlim);
|
||||
}
|
||||
|
||||
if ($flip) {
|
||||
for ($i = $ylim - 1; $i >= $yoff; $i--) {
|
||||
$ymatches[$this->xv[$i]][] = $i;
|
||||
}
|
||||
} else {
|
||||
for ($i = $ylim - 1; $i >= $yoff; $i--) {
|
||||
$ymatches[$this->yv[$i]][] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
$this->lcs = 0;
|
||||
$this->seq[0]= $yoff - 1;
|
||||
$this->in_seq = array();
|
||||
$ymids[0] = array();
|
||||
|
||||
$numer = $xlim - $xoff + $nchunks - 1;
|
||||
$x = $xoff;
|
||||
for ($chunk = 0; $chunk < $nchunks; $chunk++) {
|
||||
if ($chunk > 0) {
|
||||
for ($i = 0; $i <= $this->lcs; $i++) {
|
||||
$ymids[$i][$chunk - 1] = $this->seq[$i];
|
||||
}
|
||||
}
|
||||
|
||||
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks);
|
||||
for (; $x < $x1; $x++) {
|
||||
$line = $flip ? $this->yv[$x] : $this->xv[$x];
|
||||
if (empty($ymatches[$line])) {
|
||||
continue;
|
||||
}
|
||||
$matches = $ymatches[$line];
|
||||
reset($matches);
|
||||
while (($y = current($matches)) !== false) {
|
||||
if (empty($this->in_seq[$y])) {
|
||||
$k = $this->_lcsPos($y);
|
||||
assert($k > 0);
|
||||
$ymids[$k] = $ymids[$k - 1];
|
||||
break;
|
||||
}
|
||||
next($matches);
|
||||
}
|
||||
while (($y = current($matches)) !== false) {
|
||||
if ($y > $this->seq[$k - 1]) {
|
||||
assert($y <= $this->seq[$k]);
|
||||
/* Optimization: this is a common case: next match is
|
||||
* just replacing previous match. */
|
||||
$this->in_seq[$this->seq[$k]] = false;
|
||||
$this->seq[$k] = $y;
|
||||
$this->in_seq[$y] = 1;
|
||||
} elseif (empty($this->in_seq[$y])) {
|
||||
$k = $this->_lcsPos($y);
|
||||
assert($k > 0);
|
||||
$ymids[$k] = $ymids[$k - 1];
|
||||
}
|
||||
next($matches);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
|
||||
$ymid = $ymids[$this->lcs];
|
||||
for ($n = 0; $n < $nchunks - 1; $n++) {
|
||||
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
|
||||
$y1 = $ymid[$n] + 1;
|
||||
$seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
|
||||
}
|
||||
$seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
|
||||
|
||||
return array($this->lcs, $seps);
|
||||
}
|
||||
|
||||
protected function _lcsPos($ypos)
|
||||
{
|
||||
$end = $this->lcs;
|
||||
if ($end == 0 || $ypos > $this->seq[$end]) {
|
||||
$this->seq[++$this->lcs] = $ypos;
|
||||
$this->in_seq[$ypos] = 1;
|
||||
return $this->lcs;
|
||||
}
|
||||
|
||||
$beg = 1;
|
||||
while ($beg < $end) {
|
||||
$mid = (int)(($beg + $end) / 2);
|
||||
if ($ypos > $this->seq[$mid]) {
|
||||
$beg = $mid + 1;
|
||||
} else {
|
||||
$end = $mid;
|
||||
}
|
||||
}
|
||||
|
||||
assert($ypos != $this->seq[$end]);
|
||||
|
||||
$this->in_seq[$this->seq[$end]] = false;
|
||||
$this->seq[$end] = $ypos;
|
||||
$this->in_seq[$ypos] = 1;
|
||||
return $end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds LCS of two sequences.
|
||||
*
|
||||
* The results are recorded in the vectors $this->{x,y}changed[], by
|
||||
* storing a 1 in the element for each line that is an insertion or
|
||||
* deletion (ie. is not in the LCS).
|
||||
*
|
||||
* The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1.
|
||||
*
|
||||
* Note that XLIM, YLIM are exclusive bounds. All line numbers are
|
||||
* origin-0 and discarded lines are not counted.
|
||||
*/
|
||||
protected function _compareseq ($xoff, $xlim, $yoff, $ylim)
|
||||
{
|
||||
/* Slide down the bottom initial diagonal. */
|
||||
while ($xoff < $xlim && $yoff < $ylim
|
||||
&& $this->xv[$xoff] == $this->yv[$yoff]) {
|
||||
++$xoff;
|
||||
++$yoff;
|
||||
}
|
||||
|
||||
/* Slide up the top initial diagonal. */
|
||||
while ($xlim > $xoff && $ylim > $yoff
|
||||
&& $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
|
||||
--$xlim;
|
||||
--$ylim;
|
||||
}
|
||||
|
||||
if ($xoff == $xlim || $yoff == $ylim) {
|
||||
$lcs = 0;
|
||||
} else {
|
||||
/* This is ad hoc but seems to work well. $nchunks =
|
||||
* sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); $nchunks =
|
||||
* max(2,min(8,(int)$nchunks)); */
|
||||
$nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
|
||||
list($lcs, $seps)
|
||||
= $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
|
||||
}
|
||||
|
||||
if ($lcs == 0) {
|
||||
/* X and Y sequences have no common subsequence: mark all
|
||||
* changed. */
|
||||
while ($yoff < $ylim) {
|
||||
$this->ychanged[$this->yind[$yoff++]] = 1;
|
||||
}
|
||||
while ($xoff < $xlim) {
|
||||
$this->xchanged[$this->xind[$xoff++]] = 1;
|
||||
}
|
||||
} else {
|
||||
/* Use the partitions to split this problem into subproblems. */
|
||||
reset($seps);
|
||||
$pt1 = $seps[0];
|
||||
while ($pt2 = next($seps)) {
|
||||
$this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
|
||||
$pt1 = $pt2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts inserts/deletes of identical lines to join changes as much as
|
||||
* possible.
|
||||
*
|
||||
* We do something when a run of changed lines include a line at one end
|
||||
* and has an excluded, identical line at the other. We are free to
|
||||
* choose which identical line is included. `compareseq' usually chooses
|
||||
* the one at the beginning, but usually it is cleaner to consider the
|
||||
* following identical line to be the "change".
|
||||
*
|
||||
* This is extracted verbatim from analyze.c (GNU diffutils-2.7).
|
||||
*/
|
||||
protected function _shiftBoundaries($lines, &$changed, $other_changed)
|
||||
{
|
||||
$i = 0;
|
||||
$j = 0;
|
||||
|
||||
assert(count($lines) == count($changed));
|
||||
$len = count($lines);
|
||||
$other_len = count($other_changed);
|
||||
|
||||
while (1) {
|
||||
/* Scan forward to find the beginning of another run of
|
||||
* changes. Also keep track of the corresponding point in the
|
||||
* other file.
|
||||
*
|
||||
* Throughout this code, $i and $j are adjusted together so that
|
||||
* the first $i elements of $changed and the first $j elements of
|
||||
* $other_changed both contain the same number of zeros (unchanged
|
||||
* lines).
|
||||
*
|
||||
* Furthermore, $j is always kept so that $j == $other_len or
|
||||
* $other_changed[$j] == false. */
|
||||
while ($j < $other_len && $other_changed[$j]) {
|
||||
$j++;
|
||||
}
|
||||
|
||||
while ($i < $len && ! $changed[$i]) {
|
||||
assert($j < $other_len && ! $other_changed[$j]);
|
||||
$i++; $j++;
|
||||
while ($j < $other_len && $other_changed[$j]) {
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($i == $len) {
|
||||
break;
|
||||
}
|
||||
|
||||
$start = $i;
|
||||
|
||||
/* Find the end of this run of changes. */
|
||||
while (++$i < $len && $changed[$i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
do {
|
||||
/* Record the length of this run of changes, so that we can
|
||||
* later determine whether the run has grown. */
|
||||
$runlength = $i - $start;
|
||||
|
||||
/* Move the changed region back, so long as the previous
|
||||
* unchanged line matches the last changed one. This merges
|
||||
* with previous changed regions. */
|
||||
while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
|
||||
$changed[--$start] = 1;
|
||||
$changed[--$i] = false;
|
||||
while ($start > 0 && $changed[$start - 1]) {
|
||||
$start--;
|
||||
}
|
||||
assert($j > 0);
|
||||
while ($other_changed[--$j]) {
|
||||
continue;
|
||||
}
|
||||
assert($j >= 0 && !$other_changed[$j]);
|
||||
}
|
||||
|
||||
/* Set CORRESPONDING to the end of the changed run, at the
|
||||
* last point where it corresponds to a changed run in the
|
||||
* other file. CORRESPONDING == LEN means no such point has
|
||||
* been found. */
|
||||
$corresponding = $j < $other_len ? $i : $len;
|
||||
|
||||
/* Move the changed region forward, so long as the first
|
||||
* changed line matches the following unchanged one. This
|
||||
* merges with following changed regions. Do this second, so
|
||||
* that if there are no merges, the changed region is moved
|
||||
* forward as far as possible. */
|
||||
while ($i < $len && $lines[$start] == $lines[$i]) {
|
||||
$changed[$start++] = false;
|
||||
$changed[$i++] = 1;
|
||||
while ($i < $len && $changed[$i]) {
|
||||
$i++;
|
||||
}
|
||||
|
||||
assert($j < $other_len && ! $other_changed[$j]);
|
||||
$j++;
|
||||
if ($j < $other_len && $other_changed[$j]) {
|
||||
$corresponding = $i;
|
||||
while ($j < $other_len && $other_changed[$j]) {
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ($runlength != $i - $start);
|
||||
|
||||
/* If possible, move the fully-merged run of changes back to a
|
||||
* corresponding run in the other file. */
|
||||
while ($corresponding < $i) {
|
||||
$changed[--$start] = 1;
|
||||
$changed[--$i] = 0;
|
||||
assert($j > 0);
|
||||
while ($other_changed[--$j]) {
|
||||
continue;
|
||||
}
|
||||
assert($j >= 0 && !$other_changed[$j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
165
webroot/forum/inc/3rdparty/diff/Diff/Engine/Shell.php
vendored
Normal file
165
webroot/forum/inc/3rdparty/diff/Diff/Engine/Shell.php
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used internally by Diff to actually compute the diffs.
|
||||
*
|
||||
* This class uses the Unix `diff` program via shell_exec to compute the
|
||||
* differences between the two input arrays.
|
||||
*
|
||||
* Copyright 2007-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Milian Wolff <mail@milianw.de>
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Engine_Shell
|
||||
{
|
||||
/**
|
||||
* Path to the diff executable
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_diffCommand = 'diff';
|
||||
|
||||
/**
|
||||
* Returns the array of differences.
|
||||
*
|
||||
* @param array $from_lines lines of text from old file
|
||||
* @param array $to_lines lines of text from new file
|
||||
*
|
||||
* @return array all changes made (array with Horde_Text_Diff_Op_* objects)
|
||||
*/
|
||||
public function diff($from_lines, $to_lines)
|
||||
{
|
||||
array_walk($from_lines, array('Horde_Text_Diff', 'trimNewlines'));
|
||||
array_walk($to_lines, array('Horde_Text_Diff', 'trimNewlines'));
|
||||
|
||||
// Execute gnu diff or similar to get a standard diff file.
|
||||
$from_file = Horde_Util::getTempFile('Horde_Text_Diff');
|
||||
$to_file = Horde_Util::getTempFile('Horde_Text_Diff');
|
||||
$fp = fopen($from_file, 'w');
|
||||
fwrite($fp, implode("\n", $from_lines));
|
||||
fclose($fp);
|
||||
$fp = fopen($to_file, 'w');
|
||||
fwrite($fp, implode("\n", $to_lines));
|
||||
fclose($fp);
|
||||
$diff = shell_exec($this->_diffCommand . ' ' . $from_file . ' ' . $to_file);
|
||||
unlink($from_file);
|
||||
unlink($to_file);
|
||||
|
||||
if (is_null($diff)) {
|
||||
// No changes were made
|
||||
return array(new Horde_Text_Diff_Op_Copy($from_lines));
|
||||
}
|
||||
|
||||
$from_line_no = 1;
|
||||
$to_line_no = 1;
|
||||
$edits = array();
|
||||
|
||||
// Get changed lines by parsing something like:
|
||||
// 0a1,2
|
||||
// 1,2c4,6
|
||||
// 1,5d6
|
||||
preg_match_all('#^(\d+)(?:,(\d+))?([adc])(\d+)(?:,(\d+))?$#m', $diff,
|
||||
$matches, PREG_SET_ORDER);
|
||||
|
||||
foreach ($matches as $match) {
|
||||
if (!isset($match[5])) {
|
||||
// This paren is not set every time (see regex).
|
||||
$match[5] = false;
|
||||
}
|
||||
|
||||
if ($match[3] == 'a') {
|
||||
$from_line_no--;
|
||||
}
|
||||
|
||||
if ($match[3] == 'd') {
|
||||
$to_line_no--;
|
||||
}
|
||||
|
||||
if ($from_line_no < $match[1] || $to_line_no < $match[4]) {
|
||||
// copied lines
|
||||
assert($match[1] - $from_line_no == $match[4] - $to_line_no);
|
||||
$edits[] =
|
||||
new Horde_Text_Diff_Op_Copy(
|
||||
$this->_getLines($from_lines, $from_line_no, $match[1] - 1),
|
||||
$this->_getLines($to_lines, $to_line_no, $match[4] - 1));
|
||||
}
|
||||
|
||||
switch ($match[3]) {
|
||||
case 'd':
|
||||
// deleted lines
|
||||
$edits[] =
|
||||
new Horde_Text_Diff_Op_Delete(
|
||||
$this->_getLines($from_lines, $from_line_no, $match[2]));
|
||||
$to_line_no++;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
// changed lines
|
||||
$edits[] =
|
||||
new Horde_Text_Diff_Op_Change(
|
||||
$this->_getLines($from_lines, $from_line_no, $match[2]),
|
||||
$this->_getLines($to_lines, $to_line_no, $match[5]));
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
// added lines
|
||||
$edits[] =
|
||||
new Horde_Text_Diff_Op_Add(
|
||||
$this->_getLines($to_lines, $to_line_no, $match[5]));
|
||||
$from_line_no++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($from_lines)) {
|
||||
// Some lines might still be pending. Add them as copied
|
||||
$edits[] =
|
||||
new Horde_Text_Diff_Op_Copy(
|
||||
$this->_getLines($from_lines, $from_line_no,
|
||||
$from_line_no + count($from_lines) - 1),
|
||||
$this->_getLines($to_lines, $to_line_no,
|
||||
$to_line_no + count($to_lines) - 1));
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lines from either the old or new text
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param array &$text_lines Either $from_lines or $to_lines
|
||||
* @param int &$line_no Current line number
|
||||
* @param int $end Optional end line, when we want to chop more
|
||||
* than one line.
|
||||
*
|
||||
* @return array The chopped lines
|
||||
*/
|
||||
protected function _getLines(&$text_lines, &$line_no, $end = false)
|
||||
{
|
||||
if (!empty($end)) {
|
||||
$lines = array();
|
||||
// We can shift even more
|
||||
while ($line_no <= $end) {
|
||||
$lines[] = array_shift($text_lines);
|
||||
$line_no++;
|
||||
}
|
||||
} else {
|
||||
$lines = array(array_shift($text_lines));
|
||||
$line_no++;
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
}
|
||||
254
webroot/forum/inc/3rdparty/diff/Diff/Engine/String.php
vendored
Normal file
254
webroot/forum/inc/3rdparty/diff/Diff/Engine/String.php
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
/**
|
||||
* Parses unified or context diffs output from eg. the diff utility.
|
||||
*
|
||||
* Example:
|
||||
* <code>
|
||||
* $patch = file_get_contents('example.patch');
|
||||
* $diff = new Horde_Text_Diff('string', array($patch));
|
||||
* $renderer = new Horde_Text_Diff_Renderer_inline();
|
||||
* echo $renderer->render($diff);
|
||||
* </code>
|
||||
*
|
||||
* Copyright 2005 Örjan Persson <o@42mm.org>
|
||||
* Copyright 2005-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Örjan Persson <o@42mm.org>
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Engine_String
|
||||
{
|
||||
/**
|
||||
* Parses a unified or context diff.
|
||||
*
|
||||
* First param contains the whole diff and the second can be used to force
|
||||
* a specific diff type. If the second parameter is 'autodetect', the
|
||||
* diff will be examined to find out which type of diff this is.
|
||||
*
|
||||
* @param string $diff The diff content.
|
||||
* @param string $mode The diff mode of the content in $diff. One of
|
||||
* 'context', 'unified', or 'autodetect'.
|
||||
*
|
||||
* @return array List of all diff operations.
|
||||
* @throws Horde_Text_Diff_Exception
|
||||
*/
|
||||
public function diff($diff, $mode = 'autodetect')
|
||||
{
|
||||
// Detect line breaks.
|
||||
$lnbr = "\n";
|
||||
if (strpos($diff, "\r\n") !== false) {
|
||||
$lnbr = "\r\n";
|
||||
} elseif (strpos($diff, "\r") !== false) {
|
||||
$lnbr = "\r";
|
||||
}
|
||||
|
||||
// Make sure we have a line break at the EOF.
|
||||
if (substr($diff, -strlen($lnbr)) != $lnbr) {
|
||||
$diff .= $lnbr;
|
||||
}
|
||||
|
||||
if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') {
|
||||
throw new Horde_Text_Diff_Exception('Type of diff is unsupported');
|
||||
}
|
||||
|
||||
if ($mode == 'autodetect') {
|
||||
$context = strpos($diff, '***');
|
||||
$unified = strpos($diff, '---');
|
||||
if ($context === $unified) {
|
||||
throw new Horde_Text_Diff_Exception('Type of diff could not be detected');
|
||||
} elseif ($context === false || $unified === false) {
|
||||
$mode = $context !== false ? 'context' : 'unified';
|
||||
} else {
|
||||
$mode = $context < $unified ? 'context' : 'unified';
|
||||
}
|
||||
}
|
||||
|
||||
// Split by new line and remove the diff header, if there is one.
|
||||
$diff = explode($lnbr, $diff);
|
||||
if (($mode == 'context' && strpos($diff[0], '***') === 0) ||
|
||||
($mode == 'unified' && strpos($diff[0], '---') === 0)) {
|
||||
array_shift($diff);
|
||||
array_shift($diff);
|
||||
}
|
||||
|
||||
if ($mode == 'context') {
|
||||
return $this->parseContextDiff($diff);
|
||||
} else {
|
||||
return $this->parseUnifiedDiff($diff);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array containing the unified diff.
|
||||
*
|
||||
* @param array $diff Array of lines.
|
||||
*
|
||||
* @return array List of all diff operations.
|
||||
*/
|
||||
public function parseUnifiedDiff($diff)
|
||||
{
|
||||
$edits = array();
|
||||
$end = count($diff) - 1;
|
||||
for ($i = 0; $i < $end;) {
|
||||
$diff1 = array();
|
||||
switch (substr($diff[$i], 0, 1)) {
|
||||
case ' ':
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 1);
|
||||
} while (++$i < $end && substr($diff[$i], 0, 1) == ' ');
|
||||
$edits[] = new Horde_Text_Diff_Op_Copy($diff1);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
// get all new lines
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 1);
|
||||
} while (++$i < $end && substr($diff[$i], 0, 1) == '+');
|
||||
$edits[] = new Horde_Text_Diff_Op_Add($diff1);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
// get changed or removed lines
|
||||
$diff2 = array();
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 1);
|
||||
} while (++$i < $end && substr($diff[$i], 0, 1) == '-');
|
||||
|
||||
while ($i < $end && substr($diff[$i], 0, 1) == '+') {
|
||||
$diff2[] = substr($diff[$i++], 1);
|
||||
}
|
||||
if (count($diff2) == 0) {
|
||||
$edits[] = new Horde_Text_Diff_Op_Delete($diff1);
|
||||
} else {
|
||||
$edits[] = new Horde_Text_Diff_Op_Change($diff1, $diff2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array containing the context diff.
|
||||
*
|
||||
* @param array $diff Array of lines.
|
||||
*
|
||||
* @return array List of all diff operations.
|
||||
*/
|
||||
public function parseContextDiff(&$diff)
|
||||
{
|
||||
$edits = array();
|
||||
$i = $max_i = $j = $max_j = 0;
|
||||
$end = count($diff) - 1;
|
||||
while ($i < $end && $j < $end) {
|
||||
while ($i >= $max_i && $j >= $max_j) {
|
||||
// Find the boundaries of the diff output of the two files
|
||||
for ($i = $j;
|
||||
$i < $end && substr($diff[$i], 0, 3) == '***';
|
||||
$i++);
|
||||
for ($max_i = $i;
|
||||
$max_i < $end && substr($diff[$max_i], 0, 3) != '---';
|
||||
$max_i++);
|
||||
for ($j = $max_i;
|
||||
$j < $end && substr($diff[$j], 0, 3) == '---';
|
||||
$j++);
|
||||
for ($max_j = $j;
|
||||
$max_j < $end && substr($diff[$max_j], 0, 3) != '***';
|
||||
$max_j++);
|
||||
}
|
||||
|
||||
// find what hasn't been changed
|
||||
$array = array();
|
||||
while ($i < $max_i &&
|
||||
$j < $max_j &&
|
||||
strcmp($diff[$i], $diff[$j]) == 0) {
|
||||
$array[] = substr($diff[$i], 2);
|
||||
$i++;
|
||||
$j++;
|
||||
}
|
||||
|
||||
while ($i < $max_i && ($max_j-$j) <= 1) {
|
||||
if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {
|
||||
break;
|
||||
}
|
||||
$array[] = substr($diff[$i++], 2);
|
||||
}
|
||||
|
||||
while ($j < $max_j && ($max_i-$i) <= 1) {
|
||||
if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {
|
||||
break;
|
||||
}
|
||||
$array[] = substr($diff[$j++], 2);
|
||||
}
|
||||
if (count($array) > 0) {
|
||||
$edits[] = new Horde_Text_Diff_Op_Copy($array);
|
||||
}
|
||||
|
||||
if ($i < $max_i) {
|
||||
$diff1 = array();
|
||||
switch (substr($diff[$i], 0, 1)) {
|
||||
case '!':
|
||||
$diff2 = array();
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 2);
|
||||
if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {
|
||||
$diff2[] = substr($diff[$j++], 2);
|
||||
}
|
||||
} while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');
|
||||
$edits[] = new Horde_Text_Diff_Op_Change($diff1, $diff2);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 2);
|
||||
} while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');
|
||||
$edits[] = new Horde_Text_Diff_Op_Add($diff1);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
do {
|
||||
$diff1[] = substr($diff[$i], 2);
|
||||
} while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');
|
||||
$edits[] = new Horde_Text_Diff_Op_Delete($diff1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($j < $max_j) {
|
||||
$diff2 = array();
|
||||
switch (substr($diff[$j], 0, 1)) {
|
||||
case '+':
|
||||
do {
|
||||
$diff2[] = substr($diff[$j++], 2);
|
||||
} while ($j < $max_j && substr($diff[$j], 0, 1) == '+');
|
||||
$edits[] = new Horde_Text_Diff_Op_Add($diff2);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
do {
|
||||
$diff2[] = substr($diff[$j++], 2);
|
||||
} while ($j < $max_j && substr($diff[$j], 0, 1) == '-');
|
||||
$edits[] = new Horde_Text_Diff_Op_Delete($diff2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
}
|
||||
74
webroot/forum/inc/3rdparty/diff/Diff/Engine/Xdiff.php
vendored
Normal file
74
webroot/forum/inc/3rdparty/diff/Diff/Engine/Xdiff.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* Class used internally by Diff to actually compute the diffs.
|
||||
*
|
||||
* This class uses the xdiff PECL package (http://pecl.php.net/package/xdiff)
|
||||
* to compute the differences between the two input arrays.
|
||||
*
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Jon Parise <jon@horde.org>
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Engine_Xdiff
|
||||
{
|
||||
/**
|
||||
*/
|
||||
public function diff($from_lines, $to_lines)
|
||||
{
|
||||
if (!extension_loaded('xdiff')) {
|
||||
throw new Horde_Text_Diff_Exception('The xdiff extension is required for this diff engine');
|
||||
}
|
||||
|
||||
array_walk($from_lines, array('Horde_Text_Diff', 'trimNewlines'));
|
||||
array_walk($to_lines, array('Horde_Text_Diff', 'trimNewlines'));
|
||||
|
||||
/* Convert the two input arrays into strings for xdiff processing. */
|
||||
$from_string = implode("\n", $from_lines);
|
||||
$to_string = implode("\n", $to_lines);
|
||||
|
||||
/* Diff the two strings and convert the result to an array. */
|
||||
$diff = xdiff_string_diff($from_string, $to_string, count($to_lines));
|
||||
$diff = explode("\n", $diff);
|
||||
|
||||
/* Walk through the diff one line at a time. We build the $edits
|
||||
* array of diff operations by reading the first character of the
|
||||
* xdiff output (which is in the "unified diff" format).
|
||||
*
|
||||
* Note that we don't have enough information to detect "changed"
|
||||
* lines using this approach, so we can't add Horde_Text_Diff_Op_Changed
|
||||
* instances to the $edits array. The result is still perfectly
|
||||
* valid, albeit a little less descriptive and efficient. */
|
||||
$edits = array();
|
||||
foreach ($diff as $line) {
|
||||
if (!strlen($line)) {
|
||||
continue;
|
||||
}
|
||||
switch ($line[0]) {
|
||||
case ' ':
|
||||
$edits[] = new Horde_Text_Diff_Op_Copy(array(substr($line, 1)));
|
||||
break;
|
||||
|
||||
case '+':
|
||||
$edits[] = new Horde_Text_Diff_Op_Add(array(substr($line, 1)));
|
||||
break;
|
||||
|
||||
case '-':
|
||||
$edits[] = new Horde_Text_Diff_Op_Delete(array(substr($line, 1)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
}
|
||||
8
webroot/forum/inc/3rdparty/diff/Diff/Engine/index.html
vendored
Normal file
8
webroot/forum/inc/3rdparty/diff/Diff/Engine/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
24
webroot/forum/inc/3rdparty/diff/Diff/Exception.php
vendored
Normal file
24
webroot/forum/inc/3rdparty/diff/Diff/Exception.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* Exception handler for the Text_Diff package.
|
||||
*
|
||||
* Copyright 2011-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Jan Schneider <jan@horde.org>
|
||||
* @category Horde
|
||||
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Exception extends Horde_Exception_Wrapped
|
||||
{
|
||||
}
|
||||
68
webroot/forum/inc/3rdparty/diff/Diff/Mapped.php
vendored
Normal file
68
webroot/forum/inc/3rdparty/diff/Diff/Mapped.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2007-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* @category Horde
|
||||
* @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
/**
|
||||
* This can be used to compute things like case-insensitve diffs, or diffs
|
||||
* which ignore changes in white-space.
|
||||
*
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* @category Horde
|
||||
* @copyright 2007-2017 Horde LLC
|
||||
* @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Mapped extends Horde_Text_Diff
|
||||
{
|
||||
/**
|
||||
* Computes a diff between sequences of strings.
|
||||
*
|
||||
* @param string $engine Name of the diffing engine to use. 'auto' will
|
||||
* automatically select the best.
|
||||
* @param array $params Parameters to pass to the diffing engine:
|
||||
* - Two arrays, each containing the lines from a
|
||||
* file.
|
||||
* - Two arrays with the same size as the first
|
||||
* parameters. The elements are what is actually
|
||||
* compared when computing the diff.
|
||||
*/
|
||||
public function __construct($engine, $params)
|
||||
{
|
||||
list($from_lines, $to_lines, $mapped_from_lines, $mapped_to_lines) = $params;
|
||||
assert(count($from_lines) == count($mapped_from_lines));
|
||||
assert(count($to_lines) == count($mapped_to_lines));
|
||||
|
||||
parent::__construct($engine, array($mapped_from_lines, $mapped_to_lines));
|
||||
|
||||
$xi = $yi = 0;
|
||||
for ($i = 0; $i < count($this->_edits); $i++) {
|
||||
$orig = &$this->_edits[$i]->orig;
|
||||
if (is_array($orig)) {
|
||||
$orig = array_slice($from_lines, $xi, count($orig));
|
||||
$xi += count($orig);
|
||||
}
|
||||
|
||||
$final = &$this->_edits[$i]->final;
|
||||
if (is_array($final)) {
|
||||
$final = array_slice($to_lines, $yi, count($final));
|
||||
$yi += count($final);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
webroot/forum/inc/3rdparty/diff/Diff/Op/Add.php
vendored
Normal file
34
webroot/forum/inc/3rdparty/diff/Diff/Op/Add.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* The original PHP version of this code was written by Geoffrey T. Dairiki
|
||||
* <dairiki@dairiki.org>, and is used/adapted with his permission.
|
||||
*
|
||||
* Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Op_Add extends Horde_Text_Diff_Op_Base
|
||||
{
|
||||
public function __construct($lines)
|
||||
{
|
||||
$this->final = $lines;
|
||||
$this->orig = false;
|
||||
}
|
||||
|
||||
public function reverse()
|
||||
{
|
||||
return new Horde_Text_Diff_Op_Delete($this->final);
|
||||
}
|
||||
}
|
||||
38
webroot/forum/inc/3rdparty/diff/Diff/Op/Base.php
vendored
Normal file
38
webroot/forum/inc/3rdparty/diff/Diff/Op/Base.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* The original PHP version of this code was written by Geoffrey T. Dairiki
|
||||
* <dairiki@dairiki.org>, and is used/adapted with his permission.
|
||||
*
|
||||
* Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
abstract class Horde_Text_Diff_Op_Base
|
||||
{
|
||||
public $orig;
|
||||
public $final;
|
||||
|
||||
abstract public function reverse();
|
||||
|
||||
public function norig()
|
||||
{
|
||||
return $this->orig ? count($this->orig) : 0;
|
||||
}
|
||||
|
||||
public function nfinal()
|
||||
{
|
||||
return $this->final ? count($this->final) : 0;
|
||||
}
|
||||
}
|
||||
34
webroot/forum/inc/3rdparty/diff/Diff/Op/Change.php
vendored
Normal file
34
webroot/forum/inc/3rdparty/diff/Diff/Op/Change.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* The original PHP version of this code was written by Geoffrey T. Dairiki
|
||||
* <dairiki@dairiki.org>, and is used/adapted with his permission.
|
||||
*
|
||||
* Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Op_Change extends Horde_Text_Diff_Op_Base
|
||||
{
|
||||
public function __construct($orig, $final)
|
||||
{
|
||||
$this->orig = $orig;
|
||||
$this->final = $final;
|
||||
}
|
||||
|
||||
public function reverse()
|
||||
{
|
||||
return new Horde_Text_Diff_Op_Change($this->final, $this->orig);
|
||||
}
|
||||
}
|
||||
37
webroot/forum/inc/3rdparty/diff/Diff/Op/Copy.php
vendored
Normal file
37
webroot/forum/inc/3rdparty/diff/Diff/Op/Copy.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* The original PHP version of this code was written by Geoffrey T. Dairiki
|
||||
* <dairiki@dairiki.org>, and is used/adapted with his permission.
|
||||
*
|
||||
* Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Op_Copy extends Horde_Text_Diff_Op_Base
|
||||
{
|
||||
public function __construct($orig, $final = false)
|
||||
{
|
||||
if (!is_array($final)) {
|
||||
$final = $orig;
|
||||
}
|
||||
$this->orig = $orig;
|
||||
$this->final = $final;
|
||||
}
|
||||
|
||||
public function reverse()
|
||||
{
|
||||
return new Horde_Text_Diff_Op_Copy($this->final, $this->orig);
|
||||
}
|
||||
}
|
||||
34
webroot/forum/inc/3rdparty/diff/Diff/Op/Delete.php
vendored
Normal file
34
webroot/forum/inc/3rdparty/diff/Diff/Op/Delete.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* The original PHP version of this code was written by Geoffrey T. Dairiki
|
||||
* <dairiki@dairiki.org>, and is used/adapted with his permission.
|
||||
*
|
||||
* Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Op_Delete extends Horde_Text_Diff_Op_Base
|
||||
{
|
||||
public function __construct($lines)
|
||||
{
|
||||
$this->orig = $lines;
|
||||
$this->final = false;
|
||||
}
|
||||
|
||||
public function reverse()
|
||||
{
|
||||
return new Horde_Text_Diff_Op_Add($this->orig);
|
||||
}
|
||||
}
|
||||
8
webroot/forum/inc/3rdparty/diff/Diff/Op/index.html
vendored
Normal file
8
webroot/forum/inc/3rdparty/diff/Diff/Op/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
241
webroot/forum/inc/3rdparty/diff/Diff/Renderer.php
vendored
Normal file
241
webroot/forum/inc/3rdparty/diff/Diff/Renderer.php
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
/**
|
||||
* A class to render Diffs in different formats.
|
||||
*
|
||||
* This class renders the diff in classic diff format. It is intended that
|
||||
* this class be customized via inheritance, to obtain fancier outputs.
|
||||
*
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Renderer
|
||||
{
|
||||
/**
|
||||
* Number of leading context "lines" to preserve.
|
||||
*
|
||||
* This should be left at zero for this class, but subclasses may want to
|
||||
* set this to other values.
|
||||
*/
|
||||
protected $_leading_context_lines = 0;
|
||||
|
||||
/**
|
||||
* Number of trailing context "lines" to preserve.
|
||||
*
|
||||
* This should be left at zero for this class, but subclasses may want to
|
||||
* set this to other values.
|
||||
*/
|
||||
protected $_trailing_context_lines = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct($params = array())
|
||||
{
|
||||
foreach ($params as $param => $value) {
|
||||
$v = '_' . $param;
|
||||
if (isset($this->$v)) {
|
||||
$this->$v = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any renderer parameters.
|
||||
*
|
||||
* @return array All parameters of this renderer object.
|
||||
*/
|
||||
public function getParams()
|
||||
{
|
||||
$params = array();
|
||||
foreach (get_object_vars($this) as $k => $v) {
|
||||
if ($k[0] == '_') {
|
||||
$params[substr($k, 1)] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a diff.
|
||||
*
|
||||
* @param Horde_Text_Diff $diff A Horde_Text_Diff object.
|
||||
*
|
||||
* @return string The formatted output.
|
||||
*/
|
||||
public function render($diff)
|
||||
{
|
||||
$xi = $yi = 1;
|
||||
$block = false;
|
||||
$context = array();
|
||||
|
||||
$nlead = $this->_leading_context_lines;
|
||||
$ntrail = $this->_trailing_context_lines;
|
||||
|
||||
$output = $this->_startDiff();
|
||||
|
||||
$diffs = $diff->getDiff();
|
||||
foreach ($diffs as $i => $edit) {
|
||||
/* If these are unchanged (copied) lines, and we want to keep
|
||||
* leading or trailing context lines, extract them from the copy
|
||||
* block. */
|
||||
if ($edit instanceof Horde_Text_Diff_Op_Copy) {
|
||||
/* Do we have any diff blocks yet? */
|
||||
if (is_array($block)) {
|
||||
/* How many lines to keep as context from the copy
|
||||
* block. */
|
||||
$keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
|
||||
if (count($edit->orig) <= $keep) {
|
||||
/* We have less lines in the block than we want for
|
||||
* context => keep the whole block. */
|
||||
$block[] = $edit;
|
||||
} else {
|
||||
if ($ntrail) {
|
||||
/* Create a new block with as many lines as we need
|
||||
* for the trailing context. */
|
||||
$context = array_slice($edit->orig, 0, $ntrail);
|
||||
$block[] = new Horde_Text_Diff_Op_Copy($context);
|
||||
}
|
||||
/* @todo */
|
||||
$output .= $this->_block($x0, $ntrail + $xi - $x0,
|
||||
$y0, $ntrail + $yi - $y0,
|
||||
$block);
|
||||
$block = false;
|
||||
}
|
||||
}
|
||||
/* Keep the copy block as the context for the next block. */
|
||||
$context = $edit->orig;
|
||||
} else {
|
||||
/* Don't we have any diff blocks yet? */
|
||||
if (!is_array($block)) {
|
||||
/* Extract context lines from the preceding copy block. */
|
||||
$context = array_slice($context, count($context) - $nlead);
|
||||
$x0 = $xi - count($context);
|
||||
$y0 = $yi - count($context);
|
||||
$block = array();
|
||||
if ($context) {
|
||||
$block[] = new Horde_Text_Diff_Op_Copy($context);
|
||||
}
|
||||
}
|
||||
$block[] = $edit;
|
||||
}
|
||||
|
||||
if ($edit->orig) {
|
||||
$xi += count($edit->orig);
|
||||
}
|
||||
if ($edit->final) {
|
||||
$yi += count($edit->final);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($block)) {
|
||||
$output .= $this->_block($x0, $xi - $x0,
|
||||
$y0, $yi - $y0,
|
||||
$block);
|
||||
}
|
||||
|
||||
return $output . $this->_endDiff();
|
||||
}
|
||||
|
||||
protected function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
|
||||
{
|
||||
$output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
|
||||
|
||||
foreach ($edits as $edit) {
|
||||
switch (get_class($edit)) {
|
||||
case 'Horde_Text_Diff_Op_Copy':
|
||||
$output .= $this->_context($edit->orig);
|
||||
break;
|
||||
|
||||
case 'Horde_Text_Diff_Op_Add':
|
||||
$output .= $this->_added($edit->final);
|
||||
break;
|
||||
|
||||
case 'Horde_Text_Diff_Op_Delete':
|
||||
$output .= $this->_deleted($edit->orig);
|
||||
break;
|
||||
|
||||
case 'Horde_Text_Diff_Op_Change':
|
||||
$output .= $this->_changed($edit->orig, $edit->final);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $output . $this->_endBlock();
|
||||
}
|
||||
|
||||
protected function _startDiff()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function _endDiff()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
{
|
||||
if ($xlen > 1) {
|
||||
$xbeg .= ',' . ($xbeg + $xlen - 1);
|
||||
}
|
||||
if ($ylen > 1) {
|
||||
$ybeg .= ',' . ($ybeg + $ylen - 1);
|
||||
}
|
||||
|
||||
// this matches the GNU Diff behaviour
|
||||
if ($xlen && !$ylen) {
|
||||
$ybeg--;
|
||||
} elseif (!$xlen) {
|
||||
$xbeg--;
|
||||
}
|
||||
|
||||
return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
|
||||
}
|
||||
|
||||
protected function _startBlock($header)
|
||||
{
|
||||
return $header . "\n";
|
||||
}
|
||||
|
||||
protected function _endBlock()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function _lines($lines, $prefix = ' ')
|
||||
{
|
||||
return $prefix . implode("\n$prefix", $lines) . "\n";
|
||||
}
|
||||
|
||||
protected function _context($lines)
|
||||
{
|
||||
return $this->_lines($lines, ' ');
|
||||
}
|
||||
|
||||
protected function _added($lines)
|
||||
{
|
||||
return $this->_lines($lines, '> ');
|
||||
}
|
||||
|
||||
protected function _deleted($lines)
|
||||
{
|
||||
return $this->_lines($lines, '< ');
|
||||
}
|
||||
|
||||
protected function _changed($orig, $final)
|
||||
{
|
||||
return $this->_deleted($orig) . "---\n" . $this->_added($final);
|
||||
}
|
||||
}
|
||||
75
webroot/forum/inc/3rdparty/diff/Diff/Renderer/Context.php
vendored
Normal file
75
webroot/forum/inc/3rdparty/diff/Diff/Renderer/Context.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* "Context" diff renderer.
|
||||
*
|
||||
* This class renders the diff in classic "context diff" format.
|
||||
*
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Renderer_Context extends Horde_Text_Diff_Renderer
|
||||
{
|
||||
/**
|
||||
* Number of leading context "lines" to preserve.
|
||||
*/
|
||||
protected $_leading_context_lines = 4;
|
||||
|
||||
/**
|
||||
* Number of trailing context "lines" to preserve.
|
||||
*/
|
||||
protected $_trailing_context_lines = 4;
|
||||
|
||||
protected $_second_block = '';
|
||||
|
||||
protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
{
|
||||
if ($xlen != 1) {
|
||||
$xbeg .= ',' . $xlen;
|
||||
}
|
||||
if ($ylen != 1) {
|
||||
$ybeg .= ',' . $ylen;
|
||||
}
|
||||
$this->_second_block = "--- $ybeg ----\n";
|
||||
return "***************\n*** $xbeg ****";
|
||||
}
|
||||
|
||||
protected function _endBlock()
|
||||
{
|
||||
return $this->_second_block;
|
||||
}
|
||||
|
||||
protected function _context($lines)
|
||||
{
|
||||
$this->_second_block .= $this->_lines($lines, ' ');
|
||||
return $this->_lines($lines, ' ');
|
||||
}
|
||||
|
||||
protected function _added($lines)
|
||||
{
|
||||
$this->_second_block .= $this->_lines($lines, '+ ');
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function _deleted($lines)
|
||||
{
|
||||
return $this->_lines($lines, '- ');
|
||||
}
|
||||
|
||||
protected function _changed($orig, $final)
|
||||
{
|
||||
$this->_second_block .= $this->_lines($final, '! ');
|
||||
return $this->_lines($orig, '! ');
|
||||
}
|
||||
|
||||
}
|
||||
200
webroot/forum/inc/3rdparty/diff/Diff/Renderer/Inline.php
vendored
Normal file
200
webroot/forum/inc/3rdparty/diff/Diff/Renderer/Inline.php
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
/**
|
||||
* "Inline" diff renderer.
|
||||
*
|
||||
* This class renders diffs in the Wiki-style "inline" format.
|
||||
*
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Ciprian Popovici
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Renderer_Inline extends Horde_Text_Diff_Renderer
|
||||
{
|
||||
/**
|
||||
* Number of leading context "lines" to preserve.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $_leading_context_lines = 10000;
|
||||
|
||||
/**
|
||||
* Number of trailing context "lines" to preserve.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $_trailing_context_lines = 10000;
|
||||
|
||||
/**
|
||||
* Prefix for inserted text.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_ins_prefix = '<ins>';
|
||||
|
||||
/**
|
||||
* Suffix for inserted text.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_ins_suffix = '</ins>';
|
||||
|
||||
/**
|
||||
* Prefix for deleted text.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_del_prefix = '<del>';
|
||||
|
||||
/**
|
||||
* Suffix for deleted text.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_del_suffix = '</del>';
|
||||
|
||||
/**
|
||||
* Header for each change block.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_block_header = '';
|
||||
|
||||
/**
|
||||
* Whether to split down to character-level.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $_split_characters = false;
|
||||
|
||||
/**
|
||||
* What are we currently splitting on? Used to recurse to show word-level
|
||||
* or character-level changes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_split_level = 'lines';
|
||||
|
||||
protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
{
|
||||
return $this->_block_header;
|
||||
}
|
||||
|
||||
protected function _startBlock($header)
|
||||
{
|
||||
return $header;
|
||||
}
|
||||
|
||||
protected function _lines($lines, $prefix = ' ', $encode = true)
|
||||
{
|
||||
if ($encode) {
|
||||
array_walk($lines, array(&$this, '_encode'));
|
||||
}
|
||||
|
||||
if ($this->_split_level == 'lines') {
|
||||
return implode("\n", $lines) . "\n";
|
||||
} else {
|
||||
return implode('', $lines);
|
||||
}
|
||||
}
|
||||
|
||||
protected function _added($lines)
|
||||
{
|
||||
array_walk($lines, array(&$this, '_encode'));
|
||||
$lines[0] = $this->_ins_prefix . $lines[0];
|
||||
$lines[count($lines) - 1] .= $this->_ins_suffix;
|
||||
return $this->_lines($lines, ' ', false);
|
||||
}
|
||||
|
||||
protected function _deleted($lines, $words = false)
|
||||
{
|
||||
array_walk($lines, array(&$this, '_encode'));
|
||||
$lines[0] = $this->_del_prefix . $lines[0];
|
||||
$lines[count($lines) - 1] .= $this->_del_suffix;
|
||||
return $this->_lines($lines, ' ', false);
|
||||
}
|
||||
|
||||
protected function _changed($orig, $final)
|
||||
{
|
||||
/* If we've already split on characters, just display. */
|
||||
if ($this->_split_level == 'characters') {
|
||||
return $this->_deleted($orig)
|
||||
. $this->_added($final);
|
||||
}
|
||||
|
||||
/* If we've already split on words, just display. */
|
||||
if ($this->_split_level == 'words') {
|
||||
$prefix = '';
|
||||
while ($orig[0] !== false && $final[0] !== false &&
|
||||
substr($orig[0], 0, 1) == ' ' &&
|
||||
substr($final[0], 0, 1) == ' ') {
|
||||
$prefix .= substr($orig[0], 0, 1);
|
||||
$orig[0] = substr($orig[0], 1);
|
||||
$final[0] = substr($final[0], 1);
|
||||
}
|
||||
return $prefix . $this->_deleted($orig) . $this->_added($final);
|
||||
}
|
||||
|
||||
$text1 = implode("\n", $orig);
|
||||
$text2 = implode("\n", $final);
|
||||
|
||||
/* Non-printing newline marker. */
|
||||
$nl = "\0";
|
||||
|
||||
if ($this->_split_characters) {
|
||||
$diff = new Horde_Text_Diff('native',
|
||||
array(preg_split('//u', str_replace("\n", $nl, $text1)),
|
||||
preg_split('//u', str_replace("\n", $nl, $text2))));
|
||||
} else {
|
||||
/* We want to split on word boundaries, but we need to preserve
|
||||
* whitespace as well. Therefore we split on words, but include
|
||||
* all blocks of whitespace in the wordlist. */
|
||||
$diff = new Horde_Text_Diff('native',
|
||||
array($this->_splitOnWords($text1, $nl),
|
||||
$this->_splitOnWords($text2, $nl)));
|
||||
}
|
||||
|
||||
/* Get the diff in inline format. */
|
||||
$renderer = new Horde_Text_Diff_Renderer_inline
|
||||
(array_merge($this->getParams(),
|
||||
array('split_level' => $this->_split_characters ? 'characters' : 'words')));
|
||||
|
||||
/* Run the diff and get the output. */
|
||||
return str_replace($nl, "\n", $renderer->render($diff)) . "\n";
|
||||
}
|
||||
|
||||
protected function _splitOnWords($string, $newlineEscape = "\n")
|
||||
{
|
||||
// Ignore \0; otherwise the while loop will never finish.
|
||||
$string = str_replace("\0", '', $string);
|
||||
|
||||
$words = array();
|
||||
$length = strlen($string);
|
||||
$pos = 0;
|
||||
|
||||
while ($pos < $length) {
|
||||
// Eat a word with any preceding whitespace.
|
||||
$spaces = strspn(substr($string, $pos), " \n");
|
||||
$nextpos = strcspn(substr($string, $pos + $spaces), " \n");
|
||||
$words[] = str_replace("\n", $newlineEscape, substr($string, $pos, $spaces + $nextpos));
|
||||
$pos += $spaces + $nextpos;
|
||||
}
|
||||
|
||||
return $words;
|
||||
}
|
||||
|
||||
protected function _encode(&$string)
|
||||
{
|
||||
$string = htmlspecialchars($string);
|
||||
}
|
||||
}
|
||||
64
webroot/forum/inc/3rdparty/diff/Diff/Renderer/Unified.php
vendored
Normal file
64
webroot/forum/inc/3rdparty/diff/Diff/Renderer/Unified.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* "Unified" diff renderer.
|
||||
*
|
||||
* This class renders the diff in classic "unified diff" format.
|
||||
*
|
||||
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Ciprian Popovici
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Renderer_Unified extends Horde_Text_Diff_Renderer
|
||||
{
|
||||
/**
|
||||
* Number of leading context "lines" to preserve.
|
||||
*/
|
||||
protected $_leading_context_lines = 4;
|
||||
|
||||
/**
|
||||
* Number of trailing context "lines" to preserve.
|
||||
*/
|
||||
protected $_trailing_context_lines = 4;
|
||||
|
||||
protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
{
|
||||
if ($xlen != 1) {
|
||||
$xbeg .= ',' . $xlen;
|
||||
}
|
||||
if ($ylen != 1) {
|
||||
$ybeg .= ',' . $ylen;
|
||||
}
|
||||
return "@@ -$xbeg +$ybeg @@";
|
||||
}
|
||||
|
||||
protected function _context($lines)
|
||||
{
|
||||
return $this->_lines($lines, ' ');
|
||||
}
|
||||
|
||||
protected function _added($lines)
|
||||
{
|
||||
return $this->_lines($lines, '+');
|
||||
}
|
||||
|
||||
protected function _deleted($lines)
|
||||
{
|
||||
return $this->_lines($lines, '-');
|
||||
}
|
||||
|
||||
protected function _changed($orig, $final)
|
||||
{
|
||||
return $this->_deleted($orig) . $this->_added($final);
|
||||
}
|
||||
}
|
||||
74
webroot/forum/inc/3rdparty/diff/Diff/Renderer/Unified/Colored.php
vendored
Normal file
74
webroot/forum/inc/3rdparty/diff/Diff/Renderer/Unified/Colored.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Jan Schneider <jan@horde.org>
|
||||
* @category Horde
|
||||
* @license http://www.horde.org/licenses/lgpl21 LGPL
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
/**
|
||||
* "Unified" diff renderer with output coloring.
|
||||
*
|
||||
* @author Jan Schneider <jan@horde.org>
|
||||
* @category Horde
|
||||
* @copyright 2017 Horde LLC
|
||||
* @license http://www.horde.org/licenses/lgpl21 LGPL
|
||||
* @package Text_Diff
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_Renderer_Unified_Colored
|
||||
extends Horde_Text_Diff_Renderer_Unified
|
||||
{
|
||||
/**
|
||||
* CLI handler.
|
||||
*
|
||||
* Contrary to the name, it supports color highlighting for HTML too.
|
||||
*
|
||||
* @var Horde_Cli
|
||||
*/
|
||||
protected $_cli;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct($params = array())
|
||||
{
|
||||
if (!isset($params['cli'])) {
|
||||
throw new BadMethodCallException('CLI handler is missing');
|
||||
}
|
||||
parent::__construct($params);
|
||||
$this->_cli = $params['cli'];
|
||||
}
|
||||
|
||||
protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
{
|
||||
return $this->_cli->color(
|
||||
'lightmagenta', parent::_blockHeader($xbeg, $xlen, $ybeg, $ylen)
|
||||
);
|
||||
}
|
||||
|
||||
protected function _added($lines)
|
||||
{
|
||||
return $this->_cli->color(
|
||||
'lightgreen', parent::_added($lines)
|
||||
);
|
||||
}
|
||||
|
||||
protected function _deleted($lines)
|
||||
{
|
||||
return $this->_cli->color(
|
||||
'lightred', parent::_deleted($lines)
|
||||
);
|
||||
}
|
||||
}
|
||||
8
webroot/forum/inc/3rdparty/diff/Diff/Renderer/index.html
vendored
Normal file
8
webroot/forum/inc/3rdparty/diff/Diff/Renderer/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
778
webroot/forum/inc/3rdparty/diff/Diff/String.php
vendored
Normal file
778
webroot/forum/inc/3rdparty/diff/Diff/String.php
vendored
Normal file
@@ -0,0 +1,778 @@
|
||||
<?php
|
||||
/**
|
||||
* The Horde_String:: class provides static methods for charset and locale
|
||||
* safe string manipulation.
|
||||
*
|
||||
* Copyright 2003-2012 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you
|
||||
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @author Jan Schneider <jan@horde.org>
|
||||
* @category Horde
|
||||
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
|
||||
* @package Util
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_String
|
||||
{
|
||||
/**
|
||||
* lower() cache.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static protected $_lowers = array();
|
||||
|
||||
/**
|
||||
* upper() cache.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static protected $_uppers = array();
|
||||
|
||||
/**
|
||||
* Converts a string from one charset to another.
|
||||
*
|
||||
* Uses the iconv or the mbstring extensions.
|
||||
* The original string is returned if conversion failed or none
|
||||
* of the extensions were available.
|
||||
*
|
||||
* @param mixed $input The data to be converted. If $input is an an
|
||||
* array, the array's values get converted
|
||||
* recursively.
|
||||
* @param string $from The string's current charset.
|
||||
* @param string $to The charset to convert the string to.
|
||||
* @param boolean $force Force conversion?
|
||||
*
|
||||
* @return mixed The converted input data.
|
||||
*/
|
||||
static public function convertCharset($input, $from, $to, $force = false)
|
||||
{
|
||||
/* Don't bother converting numbers. */
|
||||
if (is_numeric($input)) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
/* If the from and to character sets are identical, return now. */
|
||||
if (!$force && $from == $to) {
|
||||
return $input;
|
||||
}
|
||||
$from = self::lower($from);
|
||||
$to = self::lower($to);
|
||||
if (!$force && $from == $to) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
if (is_array($input)) {
|
||||
$tmp = array();
|
||||
reset($input);
|
||||
while (list($key, $val) = each($input)) {
|
||||
$tmp[self::_convertCharset($key, $from, $to)] = self::convertCharset($val, $from, $to, $force);
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
if (is_object($input)) {
|
||||
// PEAR_Error/Exception objects are almost guaranteed to contain
|
||||
// recursion, which will cause a segfault in PHP. We should never
|
||||
// reach this line, but add a check.
|
||||
if (($input instanceof Exception) ||
|
||||
($input instanceof PEAR_Error)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$input = Horde_Util::cloneObject($input);
|
||||
$vars = get_object_vars($input);
|
||||
while (list($key, $val) = each($vars)) {
|
||||
$input->$key = self::convertCharset($val, $from, $to, $force);
|
||||
}
|
||||
return $input;
|
||||
}
|
||||
|
||||
if (!is_string($input)) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
return self::_convertCharset($input, $from, $to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function used to do charset conversion.
|
||||
*
|
||||
* @param string $input See self::convertCharset().
|
||||
* @param string $from See self::convertCharset().
|
||||
* @param string $to See self::convertCharset().
|
||||
*
|
||||
* @return string The converted string.
|
||||
*/
|
||||
static protected function _convertCharset($input, $from, $to)
|
||||
{
|
||||
/* Use utf8_[en|de]code() if possible and if the string isn't too
|
||||
* large (less than 16 MB = 16 * 1024 * 1024 = 16777216 bytes) - these
|
||||
* functions use more memory. */
|
||||
if (Horde_Util::extensionExists('xml') &&
|
||||
((strlen($input) < 16777216) ||
|
||||
!Horde_Util::extensionExists('iconv') ||
|
||||
!Horde_Util::extensionExists('mbstring'))) {
|
||||
if (($to == 'utf-8') &&
|
||||
in_array($from, array('iso-8859-1', 'us-ascii', 'utf-8'))) {
|
||||
return utf8_encode($input);
|
||||
}
|
||||
|
||||
if (($from == 'utf-8') &&
|
||||
in_array($to, array('iso-8859-1', 'us-ascii', 'utf-8'))) {
|
||||
return utf8_decode($input);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try UTF7-IMAP conversions. */
|
||||
if (($from == 'utf7-imap') || ($to == 'utf7-imap')) {
|
||||
try {
|
||||
if ($from == 'utf7-imap') {
|
||||
return self::convertCharset(Horde_Imap_Client_Utf7imap::Utf7ImapToUtf8($input), 'UTF-8', $to);
|
||||
} else {
|
||||
if ($from == 'utf-8') {
|
||||
$conv = $input;
|
||||
} else {
|
||||
$conv = self::convertCharset($input, $from, 'UTF-8');
|
||||
}
|
||||
return Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($conv);
|
||||
}
|
||||
} catch (Horde_Imap_Client_Exception $e) {
|
||||
return $input;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try iconv with transliteration. */
|
||||
if (Horde_Util::extensionExists('iconv')) {
|
||||
unset($php_errormsg);
|
||||
ini_set('track_errors', 1);
|
||||
$out = @iconv($from, $to . '//TRANSLIT', $input);
|
||||
$errmsg = isset($php_errormsg);
|
||||
ini_restore('track_errors');
|
||||
if (!$errmsg) {
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try mbstring. */
|
||||
if (Horde_Util::extensionExists('mbstring')) {
|
||||
$out = @mb_convert_encoding($input, $to, self::_mbstringCharset($from));
|
||||
if (!empty($out)) {
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a string lowercase.
|
||||
*
|
||||
* @param string $string The string to be converted.
|
||||
* @param boolean $locale If true the string will be converted based on
|
||||
* a given charset, locale independent else.
|
||||
* @param string $charset If $locale is true, the charset to use when
|
||||
* converting.
|
||||
*
|
||||
* @return string The string with lowercase characters.
|
||||
*/
|
||||
static public function lower($string, $locale = false, $charset = null)
|
||||
{
|
||||
if ($locale) {
|
||||
if (Horde_Util::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
throw new InvalidArgumentException('$charset argument must not be null');
|
||||
}
|
||||
$ret = @mb_strtolower($string, self::_mbstringCharset($charset));
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
return strtolower($string);
|
||||
}
|
||||
|
||||
if (!isset(self::$_lowers[$string])) {
|
||||
$language = setlocale(LC_CTYPE, 0);
|
||||
setlocale(LC_CTYPE, 'C');
|
||||
self::$_lowers[$string] = strtolower($string);
|
||||
setlocale(LC_CTYPE, $language);
|
||||
}
|
||||
|
||||
return self::$_lowers[$string];
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a string uppercase.
|
||||
*
|
||||
* @param string $string The string to be converted.
|
||||
* @param boolean $locale If true the string will be converted based on a
|
||||
* given charset, locale independent else.
|
||||
* @param string $charset If $locale is true, the charset to use when
|
||||
* converting. If not provided the current charset.
|
||||
*
|
||||
* @return string The string with uppercase characters.
|
||||
*/
|
||||
static public function upper($string, $locale = false, $charset = null)
|
||||
{
|
||||
if ($locale) {
|
||||
if (Horde_Util::extensionExists('mbstring')) {
|
||||
if (is_null($charset)) {
|
||||
throw new InvalidArgumentException('$charset argument must not be null');
|
||||
}
|
||||
$ret = @mb_strtoupper($string, self::_mbstringCharset($charset));
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
return strtoupper($string);
|
||||
}
|
||||
|
||||
if (!isset(self::$_uppers[$string])) {
|
||||
$language = setlocale(LC_CTYPE, 0);
|
||||
setlocale(LC_CTYPE, 'C');
|
||||
self::$_uppers[$string] = strtoupper($string);
|
||||
setlocale(LC_CTYPE, $language);
|
||||
}
|
||||
|
||||
return self::$_uppers[$string];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with the first letter capitalized if it is
|
||||
* alphabetic.
|
||||
*
|
||||
* @param string $string The string to be capitalized.
|
||||
* @param boolean $locale If true the string will be converted based on a
|
||||
* given charset, locale independent else.
|
||||
* @param string $charset The charset to use, defaults to current charset.
|
||||
*
|
||||
* @return string The capitalized string.
|
||||
*/
|
||||
static public function ucfirst($string, $locale = false, $charset = null)
|
||||
{
|
||||
if ($locale) {
|
||||
if (is_null($charset)) {
|
||||
throw new InvalidArgumentException('$charset argument must not be null');
|
||||
}
|
||||
$first = self::substr($string, 0, 1, $charset);
|
||||
if (self::isAlpha($first, $charset)) {
|
||||
$string = self::upper($first, true, $charset) . self::substr($string, 1, null, $charset);
|
||||
}
|
||||
} else {
|
||||
$string = self::upper(substr($string, 0, 1), false) . substr($string, 1);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with the first letter of each word capitalized if it is
|
||||
* alphabetic.
|
||||
*
|
||||
* Sentences are splitted into words at whitestrings.
|
||||
*
|
||||
* @param string $string The string to be capitalized.
|
||||
* @param boolean $locale If true the string will be converted based on a
|
||||
* given charset, locale independent else.
|
||||
* @param string $charset The charset to use, defaults to current charset.
|
||||
*
|
||||
* @return string The capitalized string.
|
||||
*/
|
||||
static public function ucwords($string, $locale = false, $charset = null)
|
||||
{
|
||||
$words = preg_split('/(\s+)/', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
for ($i = 0, $c = count($words); $i < $c; $i += 2) {
|
||||
$words[$i] = self::ucfirst($words[$i], $locale, $charset);
|
||||
}
|
||||
return implode('', $words);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns part of a string.
|
||||
*
|
||||
* @param string $string The string to be converted.
|
||||
* @param integer $start The part's start position, zero based.
|
||||
* @param integer $length The part's length.
|
||||
* @param string $charset The charset to use when calculating the part's
|
||||
* position and length, defaults to current
|
||||
* charset.
|
||||
*
|
||||
* @return string The string's part.
|
||||
*/
|
||||
static public function substr($string, $start, $length = null,
|
||||
$charset = 'UTF-8')
|
||||
{
|
||||
if (is_null($length)) {
|
||||
$length = self::length($string, $charset) - $start;
|
||||
}
|
||||
|
||||
if ($length == 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/* Try mbstring. */
|
||||
if (Horde_Util::extensionExists('mbstring')) {
|
||||
$ret = @mb_substr($string, $start, $length, self::_mbstringCharset($charset));
|
||||
|
||||
/* mb_substr() returns empty string on failure. */
|
||||
if (strlen($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try iconv. */
|
||||
if (Horde_Util::extensionExists('iconv')) {
|
||||
$ret = @iconv_substr($string, $start, $length, $charset);
|
||||
|
||||
/* iconv_substr() returns false on failure. */
|
||||
if ($ret !== false) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
return substr($string, $start, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character (not byte) length of a string.
|
||||
*
|
||||
* @param string $string The string to return the length of.
|
||||
* @param string $charset The charset to use when calculating the string's
|
||||
* length.
|
||||
*
|
||||
* @return integer The string's length.
|
||||
*/
|
||||
static public function length($string, $charset = 'UTF-8')
|
||||
{
|
||||
$charset = self::lower($charset);
|
||||
|
||||
if ($charset == 'utf-8' || $charset == 'utf8') {
|
||||
return strlen(utf8_decode($string));
|
||||
}
|
||||
|
||||
if (Horde_Util::extensionExists('mbstring')) {
|
||||
$ret = @mb_strlen($string, self::_mbstringCharset($charset));
|
||||
if (!empty($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numeric position of the first occurrence of $needle
|
||||
* in the $haystack string.
|
||||
*
|
||||
* @param string $haystack The string to search through.
|
||||
* @param string $needle The string to search for.
|
||||
* @param integer $offset Allows to specify which character in haystack
|
||||
* to start searching.
|
||||
* @param string $charset The charset to use when searching for the
|
||||
* $needle string.
|
||||
*
|
||||
* @return integer The position of first occurrence.
|
||||
*/
|
||||
static public function pos($haystack, $needle, $offset = 0,
|
||||
$charset = 'UTF-8')
|
||||
{
|
||||
if (Horde_Util::extensionExists('mbstring')) {
|
||||
$track_errors = ini_set('track_errors', 1);
|
||||
$ret = @mb_strpos($haystack, $needle, $offset, self::_mbstringCharset($charset));
|
||||
ini_set('track_errors', $track_errors);
|
||||
if (!isset($php_errormsg)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
return strpos($haystack, $needle, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numeric position of the last occurrence of $needle
|
||||
* in the $haystack string.
|
||||
*
|
||||
* @param string $haystack The string to search through.
|
||||
* @param string $needle The string to search for.
|
||||
* @param integer $offset Allows to specify which character in haystack
|
||||
* to start searching.
|
||||
* @param string $charset The charset to use when searching for the
|
||||
* $needle string.
|
||||
*
|
||||
* @return integer The position of first occurrence.
|
||||
*/
|
||||
static public function rpos($haystack, $needle, $offset = 0,
|
||||
$charset = 'UTF-8')
|
||||
{
|
||||
if (Horde_Util::extensionExists('mbstring')) {
|
||||
$track_errors = ini_set('track_errors', 1);
|
||||
$ret = @mb_strrpos($haystack, $needle, $offset, self::_mbstringCharset($charset));
|
||||
ini_set('track_errors', $track_errors);
|
||||
if (!isset($php_errormsg)) {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
return strrpos($haystack, $needle, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string padded to a certain length with another string.
|
||||
* This method behaves exactly like str_pad() but is multibyte safe.
|
||||
*
|
||||
* @param string $input The string to be padded.
|
||||
* @param integer $length The length of the resulting string.
|
||||
* @param string $pad The string to pad the input string with. Must
|
||||
* be in the same charset like the input string.
|
||||
* @param const $type The padding type. One of STR_PAD_LEFT,
|
||||
* STR_PAD_RIGHT, or STR_PAD_BOTH.
|
||||
* @param string $charset The charset of the input and the padding
|
||||
* strings.
|
||||
*
|
||||
* @return string The padded string.
|
||||
*/
|
||||
static public function pad($input, $length, $pad = ' ',
|
||||
$type = STR_PAD_RIGHT, $charset = 'UTF-8')
|
||||
{
|
||||
$mb_length = self::length($input, $charset);
|
||||
$sb_length = strlen($input);
|
||||
$pad_length = self::length($pad, $charset);
|
||||
|
||||
/* Return if we already have the length. */
|
||||
if ($mb_length >= $length) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
/* Shortcut for single byte strings. */
|
||||
if ($mb_length == $sb_length && $pad_length == strlen($pad)) {
|
||||
return str_pad($input, $length, $pad, $type);
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case STR_PAD_LEFT:
|
||||
$left = $length - $mb_length;
|
||||
$output = self::substr(str_repeat($pad, ceil($left / $pad_length)), 0, $left, $charset) . $input;
|
||||
break;
|
||||
|
||||
case STR_PAD_BOTH:
|
||||
$left = floor(($length - $mb_length) / 2);
|
||||
$right = ceil(($length - $mb_length) / 2);
|
||||
$output = self::substr(str_repeat($pad, ceil($left / $pad_length)), 0, $left, $charset) .
|
||||
$input .
|
||||
self::substr(str_repeat($pad, ceil($right / $pad_length)), 0, $right, $charset);
|
||||
break;
|
||||
|
||||
case STR_PAD_RIGHT:
|
||||
$right = $length - $mb_length;
|
||||
$output = $input . self::substr(str_repeat($pad, ceil($right / $pad_length)), 0, $right, $charset);
|
||||
break;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the text of a message.
|
||||
*
|
||||
* @param string $string String containing the text to wrap.
|
||||
* @param integer $width Wrap the string at this number of
|
||||
* characters.
|
||||
* @param string $break Character(s) to use when breaking lines.
|
||||
* @param boolean $cut Whether to cut inside words if a line
|
||||
* can't be wrapped.
|
||||
* @param boolean $line_folding Whether to apply line folding rules per
|
||||
* RFC 822 or similar. The correct break
|
||||
* characters including leading whitespace
|
||||
* have to be specified too.
|
||||
*
|
||||
* @return string String containing the wrapped text.
|
||||
*/
|
||||
static public function wordwrap($string, $width = 75, $break = "\n",
|
||||
$cut = false, $line_folding = false)
|
||||
{
|
||||
$wrapped = '';
|
||||
|
||||
while (self::length($string, 'UTF-8') > $width) {
|
||||
$line = self::substr($string, 0, $width, 'UTF-8');
|
||||
$string = self::substr($string, self::length($line, 'UTF-8'), null, 'UTF-8');
|
||||
|
||||
// Make sure we didn't cut a word, unless we want hard breaks
|
||||
// anyway.
|
||||
if (!$cut && preg_match('/^(.+?)((\s|\r?\n).*)/us', $string, $match)) {
|
||||
$line .= $match[1];
|
||||
$string = $match[2];
|
||||
}
|
||||
|
||||
// Wrap at existing line breaks.
|
||||
if (preg_match('/^(.*?)(\r?\n)(.*)$/su', $line, $match)) {
|
||||
$wrapped .= $match[1] . $match[2];
|
||||
$string = $match[3] . $string;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wrap at the last colon or semicolon followed by a whitespace if
|
||||
// doing line folding.
|
||||
if ($line_folding &&
|
||||
preg_match('/^(.*?)(;|:)(\s+.*)$/u', $line, $match)) {
|
||||
$wrapped .= $match[1] . $match[2] . $break;
|
||||
$string = $match[3] . $string;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wrap at the last whitespace of $line.
|
||||
$sub = $line_folding
|
||||
? '(.+[^\s])'
|
||||
: '(.*)';
|
||||
|
||||
if (preg_match('/^' . $sub . '(\s+)(.*)$/u', $line, $match)) {
|
||||
$wrapped .= $match[1] . $break;
|
||||
$string = ($line_folding ? $match[2] : '') . $match[3] . $string;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hard wrap if necessary.
|
||||
if ($cut) {
|
||||
$wrapped .= $line . $break;
|
||||
continue;
|
||||
}
|
||||
|
||||
$wrapped .= $line;
|
||||
}
|
||||
|
||||
return $wrapped . $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the text of a message.
|
||||
*
|
||||
* @param string $text String containing the text to wrap.
|
||||
* @param integer $length Wrap $text at this number of characters.
|
||||
* @param string $break_char Character(s) to use when breaking lines.
|
||||
* @param boolean $quote Ignore lines that are wrapped with the '>'
|
||||
* character (RFC 2646)? If true, we don't
|
||||
* remove any padding whitespace at the end of
|
||||
* the string.
|
||||
*
|
||||
* @return string String containing the wrapped text.
|
||||
*/
|
||||
static public function wrap($text, $length = 80, $break_char = "\n",
|
||||
$quote = false)
|
||||
{
|
||||
$paragraphs = array();
|
||||
|
||||
foreach (preg_split('/\r?\n/', $text) as $input) {
|
||||
if ($quote && (strpos($input, '>') === 0)) {
|
||||
$line = $input;
|
||||
} else {
|
||||
/* We need to handle the Usenet-style signature line
|
||||
* separately; since the space after the two dashes is
|
||||
* REQUIRED, we don't want to trim the line. */
|
||||
if ($input != '-- ') {
|
||||
$input = rtrim($input);
|
||||
}
|
||||
$line = self::wordwrap($input, $length, $break_char);
|
||||
}
|
||||
|
||||
$paragraphs[] = $line;
|
||||
}
|
||||
|
||||
return implode($break_char, $paragraphs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a truncated string, suitable for notifications.
|
||||
*
|
||||
* @param string $text The original string.
|
||||
* @param integer $length The maximum length.
|
||||
*
|
||||
* @return string The truncated string, if longer than $length.
|
||||
*/
|
||||
static public function truncate($text, $length = 100)
|
||||
{
|
||||
return (self::length($text) > $length)
|
||||
? rtrim(self::substr($text, 0, $length - 3)) . '...'
|
||||
: $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an abbreviated string, with characters in the middle of the
|
||||
* excessively long string replaced by '...'.
|
||||
*
|
||||
* @param string $text The original string.
|
||||
* @param integer $length The length at which to abbreviate.
|
||||
*
|
||||
* @return string The abbreviated string, if longer than $length.
|
||||
*/
|
||||
static public function abbreviate($text, $length = 20)
|
||||
{
|
||||
return (self::length($text) > $length)
|
||||
? rtrim(self::substr($text, 0, round(($length - 3) / 2))) . '...' . ltrim(self::substr($text, (($length - 3) / 2) * -1))
|
||||
: $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the common leading part of two strings.
|
||||
*
|
||||
* @param string $str1 A string.
|
||||
* @param string $str2 Another string.
|
||||
*
|
||||
* @return string The start of $str1 and $str2 that is identical in both.
|
||||
*/
|
||||
static public function common($str1, $str2)
|
||||
{
|
||||
for ($result = '', $i = 0;
|
||||
isset($str1[$i]) && isset($str2[$i]) && $str1[$i] == $str2[$i];
|
||||
$i++) {
|
||||
$result .= $str1[$i];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the every character in the parameter is an alphabetic
|
||||
* character.
|
||||
*
|
||||
* @param string $string The string to test.
|
||||
* @param string $charset The charset to use when testing the string.
|
||||
*
|
||||
* @return boolean True if the parameter was alphabetic only.
|
||||
*/
|
||||
static public function isAlpha($string, $charset)
|
||||
{
|
||||
if (!Horde_Util::extensionExists('mbstring')) {
|
||||
return ctype_alpha($string);
|
||||
}
|
||||
|
||||
$charset = self::_mbstringCharset($charset);
|
||||
$old_charset = mb_regex_encoding();
|
||||
|
||||
if ($charset != $old_charset) {
|
||||
@mb_regex_encoding($charset);
|
||||
}
|
||||
$alpha = !@mb_ereg_match('[^[:alpha:]]', $string);
|
||||
if ($charset != $old_charset) {
|
||||
@mb_regex_encoding($old_charset);
|
||||
}
|
||||
|
||||
return $alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if ever character in the parameter is a lowercase letter in
|
||||
* the current locale.
|
||||
*
|
||||
* @param string $string The string to test.
|
||||
* @param string $charset The charset to use when testing the string.
|
||||
*
|
||||
* @return boolean True if the parameter was lowercase.
|
||||
*/
|
||||
static public function isLower($string, $charset)
|
||||
{
|
||||
return ((self::lower($string, true, $charset) === $string) &&
|
||||
self::isAlpha($string, $charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if every character in the parameter is an uppercase letter
|
||||
* in the current locale.
|
||||
*
|
||||
* @param string $string The string to test.
|
||||
* @param string $charset The charset to use when testing the string.
|
||||
*
|
||||
* @return boolean True if the parameter was uppercase.
|
||||
*/
|
||||
static public function isUpper($string, $charset)
|
||||
{
|
||||
return ((self::upper($string, true, $charset) === $string) &&
|
||||
self::isAlpha($string, $charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a multibyte safe regex match search on the text provided.
|
||||
*
|
||||
* @param string $text The text to search.
|
||||
* @param array $regex The regular expressions to use, without perl
|
||||
* regex delimiters (e.g. '/' or '|').
|
||||
* @param string $charset The character set of the text.
|
||||
*
|
||||
* @return array The matches array from the first regex that matches.
|
||||
*/
|
||||
static public function regexMatch($text, $regex, $charset = null)
|
||||
{
|
||||
if (!empty($charset)) {
|
||||
$regex = self::convertCharset($regex, $charset, 'utf-8');
|
||||
$text = self::convertCharset($text, $charset, 'utf-8');
|
||||
}
|
||||
|
||||
$matches = array();
|
||||
foreach ($regex as $val) {
|
||||
if (preg_match('/' . $val . '/u', $text, $matches)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($charset)) {
|
||||
$matches = self::convertCharset($matches, 'utf-8', $charset);
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a string is valid UTF-8.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @param string $text The text to check.
|
||||
*
|
||||
* @return boolean True if valid UTF-8.
|
||||
*/
|
||||
static public function validUtf8($text)
|
||||
{
|
||||
/* Regex from:
|
||||
* http://stackoverflow.com/questions/1523460/ensuring-valid-utf-8-in-php
|
||||
*/
|
||||
return preg_match('/^(?:
|
||||
[\x09\x0A\x0D\x20-\x7E] # ASCII
|
||||
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|
||||
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|
||||
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|
||||
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|
||||
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|
||||
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|
||||
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
|
||||
)*$/xs', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround charsets that don't work with mbstring functions.
|
||||
*
|
||||
* @param string $charset The original charset.
|
||||
*
|
||||
* @return string The charset to use with mbstring functions.
|
||||
*/
|
||||
static protected function _mbstringCharset($charset)
|
||||
{
|
||||
/* mbstring functions do not handle the 'ks_c_5601-1987' &
|
||||
* 'ks_c_5601-1989' charsets. However, these charsets are used, for
|
||||
* example, by various versions of Outlook to send Korean characters.
|
||||
* Use UHC (CP949) encoding instead. See, e.g.,
|
||||
* http://lists.w3.org/Archives/Public/ietf-charsets/2001AprJun/0030.html */
|
||||
if ($charset == 'UTF-8' || $charset == 'utf-8') {
|
||||
return $charset;
|
||||
}
|
||||
if (in_array(self::lower($charset), array('ks_c_5601-1987', 'ks_c_5601-1989'))) {
|
||||
$charset = 'UHC';
|
||||
}
|
||||
|
||||
return $charset;
|
||||
}
|
||||
|
||||
}
|
||||
150
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay.php
vendored
Normal file
150
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay.php
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/**
|
||||
* A class for computing three way merges.
|
||||
*
|
||||
* Copyright 2007-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_ThreeWay
|
||||
{
|
||||
/**
|
||||
* Array of changes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_edits;
|
||||
|
||||
/**
|
||||
* Conflict counter.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $_conflictingBlocks = 0;
|
||||
|
||||
/**
|
||||
* Computes diff between 3 sequences of strings.
|
||||
*
|
||||
* @param array $orig The original lines to use.
|
||||
* @param array $final1 The first version to compare to.
|
||||
* @param array $final2 The second version to compare to.
|
||||
*/
|
||||
public function __construct($orig, $final1, $final2)
|
||||
{
|
||||
if (extension_loaded('xdiff')) {
|
||||
$engine = new Horde_Text_Diff_Engine_Xdiff();
|
||||
} else {
|
||||
$engine = new Horde_Text_Diff_Engine_Native();
|
||||
}
|
||||
|
||||
$this->_edits = $this->_diff3($engine->diff($orig, $final1),
|
||||
$engine->diff($orig, $final2));
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function mergedOutput($label1 = false, $label2 = false)
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($this->_edits as $edit) {
|
||||
if ($edit->isConflict()) {
|
||||
/* FIXME: this should probably be moved somewhere else. */
|
||||
$lines = array_merge($lines,
|
||||
array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')),
|
||||
$edit->final1,
|
||||
array("======="),
|
||||
$edit->final2,
|
||||
array('>>>>>>>' . ($label2 ? ' ' . $label2 : '')));
|
||||
$this->_conflictingBlocks++;
|
||||
} else {
|
||||
$lines = array_merge($lines, $edit->merged());
|
||||
}
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
protected function _diff3($edits1, $edits2)
|
||||
{
|
||||
$edits = array();
|
||||
$bb = new Horde_Text_Diff_ThreeWay_BlockBuilder();
|
||||
|
||||
$e1 = current($edits1);
|
||||
$e2 = current($edits2);
|
||||
while ($e1 || $e2) {
|
||||
if ($e1 && $e2 &&
|
||||
$e1 instanceof Horde_Text_Diff_Op_Copy &&
|
||||
$e2 instanceof Horde_Text_Diff_Op_Copy) {
|
||||
/* We have copy blocks from both diffs. This is the (only)
|
||||
* time we want to emit a diff3 copy block. Flush current
|
||||
* diff3 diff block, if any. */
|
||||
if ($edit = $bb->finish()) {
|
||||
$edits[] = $edit;
|
||||
}
|
||||
|
||||
$ncopy = min($e1->norig(), $e2->norig());
|
||||
assert($ncopy > 0);
|
||||
$edits[] = new Horde_Text_Diff_ThreeWay_Op_Copy(array_slice($e1->orig, 0, $ncopy));
|
||||
|
||||
if ($e1->norig() > $ncopy) {
|
||||
array_splice($e1->orig, 0, $ncopy);
|
||||
array_splice($e1->final, 0, $ncopy);
|
||||
} else {
|
||||
$e1 = next($edits1);
|
||||
}
|
||||
|
||||
if ($e2->norig() > $ncopy) {
|
||||
array_splice($e2->orig, 0, $ncopy);
|
||||
array_splice($e2->final, 0, $ncopy);
|
||||
} else {
|
||||
$e2 = next($edits2);
|
||||
}
|
||||
} else {
|
||||
if ($e1 && $e2) {
|
||||
if ($e1->orig && $e2->orig) {
|
||||
$norig = min($e1->norig(), $e2->norig());
|
||||
$orig = array_splice($e1->orig, 0, $norig);
|
||||
array_splice($e2->orig, 0, $norig);
|
||||
$bb->input($orig);
|
||||
}
|
||||
|
||||
if ($e1 instanceof Horde_Text_Diff_Op_Copy) {
|
||||
$bb->out1(array_splice($e1->final, 0, $norig));
|
||||
}
|
||||
|
||||
if ($e2 instanceof Horde_Text_Diff_Op_Copy) {
|
||||
$bb->out2(array_splice($e2->final, 0, $norig));
|
||||
}
|
||||
}
|
||||
|
||||
if ($e1 && ! $e1->orig) {
|
||||
$bb->out1($e1->final);
|
||||
$e1 = next($edits1);
|
||||
}
|
||||
if ($e2 && ! $e2->orig) {
|
||||
$bb->out2($e2->final);
|
||||
$e2 = next($edits2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($edit = $bb->finish()) {
|
||||
$edits[] = $edit;
|
||||
}
|
||||
|
||||
return $edits;
|
||||
}
|
||||
}
|
||||
71
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/BlockBuilder.php
vendored
Normal file
71
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/BlockBuilder.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2007-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_ThreeWay_BlockBuilder
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->_init();
|
||||
}
|
||||
|
||||
public function input($lines)
|
||||
{
|
||||
if ($lines) {
|
||||
$this->_append($this->orig, $lines);
|
||||
}
|
||||
}
|
||||
|
||||
public function out1($lines)
|
||||
{
|
||||
if ($lines) {
|
||||
$this->_append($this->final1, $lines);
|
||||
}
|
||||
}
|
||||
|
||||
public function out2($lines)
|
||||
{
|
||||
if ($lines) {
|
||||
$this->_append($this->final2, $lines);
|
||||
}
|
||||
}
|
||||
|
||||
public function isEmpty()
|
||||
{
|
||||
return !$this->orig && !$this->final1 && !$this->final2;
|
||||
}
|
||||
|
||||
public function finish()
|
||||
{
|
||||
if ($this->isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
$edit = new Horde_Text_Diff_ThreeWay_Op_Base($this->orig, $this->final1, $this->final2);
|
||||
$this->_init();
|
||||
return $edit;
|
||||
}
|
||||
}
|
||||
|
||||
protected function _init()
|
||||
{
|
||||
$this->orig = $this->final1 = $this->final2 = array();
|
||||
}
|
||||
|
||||
protected function _append(&$array, $lines)
|
||||
{
|
||||
array_splice($array, sizeof($array), 0, $lines);
|
||||
}
|
||||
}
|
||||
48
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/Op/Base.php
vendored
Normal file
48
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/Op/Base.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2007-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_ThreeWay_Op_Base
|
||||
{
|
||||
public function __construct($orig = false, $final1 = false, $final2 = false)
|
||||
{
|
||||
$this->orig = $orig ? $orig : array();
|
||||
$this->final1 = $final1 ? $final1 : array();
|
||||
$this->final2 = $final2 ? $final2 : array();
|
||||
}
|
||||
|
||||
public function merged()
|
||||
{
|
||||
if (!isset($this->_merged)) {
|
||||
if ($this->final1 === $this->final2) {
|
||||
$this->_merged = &$this->final1;
|
||||
} elseif ($this->final1 === $this->orig) {
|
||||
$this->_merged = &$this->final2;
|
||||
} elseif ($this->final2 === $this->orig) {
|
||||
$this->_merged = &$this->final1;
|
||||
} else {
|
||||
$this->_merged = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_merged;
|
||||
}
|
||||
|
||||
public function isConflict()
|
||||
{
|
||||
return $this->merged() === false;
|
||||
}
|
||||
}
|
||||
36
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/Op/Copy.php
vendored
Normal file
36
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/Op/Copy.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2007-2017 Horde LLC (http://www.horde.org/)
|
||||
*
|
||||
* See the enclosed file COPYING for license information (LGPL). If you did
|
||||
* not receive this file, see http://www.horde.org/licenses/lgpl21.
|
||||
*
|
||||
* @package Text_Diff
|
||||
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
class Horde_Text_Diff_ThreeWay_Op_Copy extends Horde_Text_Diff_ThreeWay_Op_Base
|
||||
{
|
||||
public function __construct($lines = false)
|
||||
{
|
||||
$this->orig = $lines ? $lines : array();
|
||||
$this->final1 = &$this->orig;
|
||||
$this->final2 = &$this->orig;
|
||||
}
|
||||
|
||||
public function merged()
|
||||
{
|
||||
return $this->orig;
|
||||
}
|
||||
|
||||
public function isConflict()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
8
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/Op/index.html
vendored
Normal file
8
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/Op/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
8
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/index.html
vendored
Normal file
8
webroot/forum/inc/3rdparty/diff/Diff/ThreeWay/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
8
webroot/forum/inc/3rdparty/diff/Diff/index.html
vendored
Normal file
8
webroot/forum/inc/3rdparty/diff/Diff/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
8
webroot/forum/inc/3rdparty/diff/index.html
vendored
Normal file
8
webroot/forum/inc/3rdparty/diff/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
8
webroot/forum/inc/3rdparty/index.html
vendored
Normal file
8
webroot/forum/inc/3rdparty/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
8
webroot/forum/inc/3rdparty/json/index.html
vendored
Normal file
8
webroot/forum/inc/3rdparty/json/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
822
webroot/forum/inc/3rdparty/json/json.php
vendored
Normal file
822
webroot/forum/inc/3rdparty/json/json.php
vendored
Normal file
@@ -0,0 +1,822 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to and from JSON format.
|
||||
*
|
||||
* JSON (JavaScript Object Notation) is a lightweight data-interchange
|
||||
* format. It is easy for humans to read and write. It is easy for machines
|
||||
* to parse and generate. It is based on a subset of the JavaScript
|
||||
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
|
||||
* This feature can also be found in Python. JSON is a text format that is
|
||||
* completely language independent but uses conventions that are familiar
|
||||
* to programmers of the C-family of languages, including C, C++, C#, Java,
|
||||
* JavaScript, Perl, TCL, and many others. These properties make JSON an
|
||||
* ideal data-interchange language.
|
||||
*
|
||||
* This package provides a simple encoder and decoder for JSON notation. It
|
||||
* is intended for use with client-side Javascript applications that make
|
||||
* use of HTTPRequest to perform server communication functions - data can
|
||||
* be encoded into JSON notation for use in a client-side javascript, or
|
||||
* decoded from incoming Javascript requests. JSON format is native to
|
||||
* Javascript, and can be directly eval()'ed with no further parsing
|
||||
* overhead
|
||||
*
|
||||
* All strings should be in ASCII or UTF-8 format!
|
||||
*
|
||||
* LICENSE: Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met: Redistributions of source code must retain the
|
||||
* above copyright notice, this list of conditions and the following
|
||||
* disclaimer. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* @category
|
||||
* @package Services_JSON
|
||||
* @author Michal Migurski <mike-json@teczno.com>
|
||||
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
|
||||
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
|
||||
* @copyright 2005 Michal Migurski
|
||||
* @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
|
||||
* @license http://www.opensource.org/licenses/bsd-license.php
|
||||
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
|
||||
*/
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_SLICE', 1);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_STR', 2);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_ARR', 3);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_OBJ', 4);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_CMT', 5);
|
||||
|
||||
/**
|
||||
* Behavior switch for Services_JSON::decode()
|
||||
*/
|
||||
define('SERVICES_JSON_LOOSE_TYPE', 16);
|
||||
|
||||
/**
|
||||
* Behavior switch for Services_JSON::decode()
|
||||
*/
|
||||
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
|
||||
|
||||
/**
|
||||
* Converts to and from JSON format.
|
||||
*
|
||||
* Brief example of use:
|
||||
*
|
||||
* <code>
|
||||
* // create a new instance of Services_JSON
|
||||
* $json = new Services_JSON();
|
||||
*
|
||||
* // convert a complexe value to JSON notation, and send it to the browser
|
||||
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
|
||||
* $output = $json->encode($value);
|
||||
*
|
||||
* print($output);
|
||||
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
|
||||
*
|
||||
* // accept incoming POST data, assumed to be in JSON notation
|
||||
* $input = file_get_contents('php://input', 1000000);
|
||||
* $value = $json->decode($input);
|
||||
* </code>
|
||||
*/
|
||||
class Services_JSON
|
||||
{
|
||||
/**
|
||||
* constructs a new JSON instance
|
||||
*
|
||||
* @param int $use object behavior flags; combine with boolean-OR
|
||||
*
|
||||
* possible values:
|
||||
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
|
||||
* "{...}" syntax creates associative arrays
|
||||
* instead of objects in decode().
|
||||
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
|
||||
* Values which can't be encoded (e.g. resources)
|
||||
* appear as NULL instead of throwing errors.
|
||||
* By default, a deeply-nested resource will
|
||||
* bubble up with an error, so all return values
|
||||
* from encode() should be checked with isError()
|
||||
*/
|
||||
function Services_JSON($use = 0)
|
||||
{
|
||||
$this->use = $use;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a string from one UTF-16 char to one UTF-8 char
|
||||
*
|
||||
* Normally should be handled by mb_convert_encoding, but
|
||||
* provides a slower PHP-only method for installations
|
||||
* that lack the multibye string extension.
|
||||
*
|
||||
* @param string $utf16 UTF-16 character
|
||||
* @return string UTF-8 character
|
||||
* @access private
|
||||
*/
|
||||
function utf162utf8($utf16)
|
||||
{
|
||||
// oh please oh please oh please oh please oh please
|
||||
if(function_exists('mb_convert_encoding')) {
|
||||
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
|
||||
}
|
||||
|
||||
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
|
||||
|
||||
switch(true) {
|
||||
case ((0x7F & $bytes) == $bytes):
|
||||
// this case should never be reached, because we are in ASCII range
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0x7F & $bytes);
|
||||
|
||||
case (0x07FF & $bytes) == $bytes:
|
||||
// return a 2-byte UTF-8 character
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0xC0 | (($bytes >> 6) & 0x1F))
|
||||
. chr(0x80 | ($bytes & 0x3F));
|
||||
|
||||
case (0xFFFF & $bytes) == $bytes:
|
||||
// return a 3-byte UTF-8 character
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0xE0 | (($bytes >> 12) & 0x0F))
|
||||
. chr(0x80 | (($bytes >> 6) & 0x3F))
|
||||
. chr(0x80 | ($bytes & 0x3F));
|
||||
}
|
||||
|
||||
// ignoring UTF-32 for now, sorry
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a string from one UTF-8 char to one UTF-16 char
|
||||
*
|
||||
* Normally should be handled by mb_convert_encoding, but
|
||||
* provides a slower PHP-only method for installations
|
||||
* that lack the multibye string extension.
|
||||
*
|
||||
* @param string $utf8 UTF-8 character
|
||||
* @return string UTF-16 character
|
||||
* @access private
|
||||
*/
|
||||
function utf82utf16($utf8)
|
||||
{
|
||||
// oh please oh please oh please oh please oh please
|
||||
if(function_exists('mb_convert_encoding')) {
|
||||
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
|
||||
}
|
||||
|
||||
switch(strlen($utf8)) {
|
||||
case 1:
|
||||
// this case should never be reached, because we are in ASCII range
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return $utf8;
|
||||
|
||||
case 2:
|
||||
// return a UTF-16 character from a 2-byte UTF-8 char
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0x07 & (ord($utf8{0}) >> 2))
|
||||
. chr((0xC0 & (ord($utf8{0}) << 6))
|
||||
| (0x3F & ord($utf8{1})));
|
||||
|
||||
case 3:
|
||||
// return a UTF-16 character from a 3-byte UTF-8 char
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr((0xF0 & (ord($utf8{0}) << 4))
|
||||
| (0x0F & (ord($utf8{1}) >> 2)))
|
||||
. chr((0xC0 & (ord($utf8{1}) << 6))
|
||||
| (0x7F & ord($utf8{2})));
|
||||
}
|
||||
|
||||
// ignoring UTF-32 for now, sorry
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* encodes an arbitrary variable into JSON format
|
||||
*
|
||||
* @param mixed $var any number, boolean, string, array, or object to be encoded.
|
||||
* see argument 1 to Services_JSON() above for array-parsing behavior.
|
||||
* if var is a strng, note that encode() always expects it
|
||||
* to be in ASCII or UTF-8 format!
|
||||
*
|
||||
* @return mixed JSON string representation of input var or an error if a problem occurs
|
||||
* @access public
|
||||
*/
|
||||
function encode($var)
|
||||
{
|
||||
switch (gettype($var)) {
|
||||
case 'boolean':
|
||||
return $var ? 'true' : 'false';
|
||||
|
||||
case 'NULL':
|
||||
return 'null';
|
||||
|
||||
case 'integer':
|
||||
return (int) $var;
|
||||
|
||||
case 'double':
|
||||
case 'float':
|
||||
return (float) $var;
|
||||
|
||||
case 'string':
|
||||
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
|
||||
$ascii = '';
|
||||
$strlen_var = strlen($var);
|
||||
|
||||
/*
|
||||
* Iterate over every character in the string,
|
||||
* escaping with a slash or encoding to UTF-8 where necessary
|
||||
*/
|
||||
for ($c = 0; $c < $strlen_var; ++$c) {
|
||||
|
||||
$ord_var_c = ord($var{$c});
|
||||
|
||||
switch (true) {
|
||||
case $ord_var_c == 0x08:
|
||||
$ascii .= '\b';
|
||||
break;
|
||||
case $ord_var_c == 0x09:
|
||||
$ascii .= '\t';
|
||||
break;
|
||||
case $ord_var_c == 0x0A:
|
||||
$ascii .= '\n';
|
||||
break;
|
||||
case $ord_var_c == 0x0C:
|
||||
$ascii .= '\f';
|
||||
break;
|
||||
case $ord_var_c == 0x0D:
|
||||
$ascii .= '\r';
|
||||
break;
|
||||
|
||||
case $ord_var_c == 0x22:
|
||||
case $ord_var_c == 0x2F:
|
||||
case $ord_var_c == 0x5C:
|
||||
// double quote, slash, slosh
|
||||
$ascii .= '\\'.$var{$c};
|
||||
break;
|
||||
|
||||
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
|
||||
// characters U-00000000 - U-0000007F (same as ASCII)
|
||||
$ascii .= $var{$c};
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xE0) == 0xC0):
|
||||
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
|
||||
$c += 1;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xF0) == 0xE0):
|
||||
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var{$c + 1}),
|
||||
ord($var{$c + 2}));
|
||||
$c += 2;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xF8) == 0xF0):
|
||||
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var{$c + 1}),
|
||||
ord($var{$c + 2}),
|
||||
ord($var{$c + 3}));
|
||||
$c += 3;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xFC) == 0xF8):
|
||||
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var{$c + 1}),
|
||||
ord($var{$c + 2}),
|
||||
ord($var{$c + 3}),
|
||||
ord($var{$c + 4}));
|
||||
$c += 4;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xFE) == 0xFC):
|
||||
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var{$c + 1}),
|
||||
ord($var{$c + 2}),
|
||||
ord($var{$c + 3}),
|
||||
ord($var{$c + 4}),
|
||||
ord($var{$c + 5}));
|
||||
$c += 5;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return '"'.$ascii.'"';
|
||||
|
||||
case 'array':
|
||||
/*
|
||||
* As per JSON spec if any array key is not an integer
|
||||
* we must treat the the whole array as an object. We
|
||||
* also try to catch a sparsely populated associative
|
||||
* array with numeric keys here because some JS engines
|
||||
* will create an array with empty indexes up to
|
||||
* max_index which can cause memory issues and because
|
||||
* the keys, which may be relevant, will be remapped
|
||||
* otherwise.
|
||||
*
|
||||
* As per the ECMA and JSON specification an object may
|
||||
* have any string as a property. Unfortunately due to
|
||||
* a hole in the ECMA specification if the key is a
|
||||
* ECMA reserved word or starts with a digit the
|
||||
* parameter is only accessible using ECMAScript's
|
||||
* bracket notation.
|
||||
*/
|
||||
|
||||
// treat as a JSON object
|
||||
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
|
||||
$properties = array_map(array($this, 'name_value'),
|
||||
array_keys($var),
|
||||
array_values($var));
|
||||
|
||||
foreach($properties as $property) {
|
||||
if(Services_JSON::isError($property)) {
|
||||
return $property;
|
||||
}
|
||||
}
|
||||
|
||||
return '{' . join(',', $properties) . '}';
|
||||
}
|
||||
|
||||
// treat it like a regular array
|
||||
$elements = array_map(array($this, 'encode'), $var);
|
||||
|
||||
foreach($elements as $element) {
|
||||
if(Services_JSON::isError($element)) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
return '[' . join(',', $elements) . ']';
|
||||
|
||||
case 'object':
|
||||
$vars = get_object_vars($var);
|
||||
|
||||
$properties = array_map(array($this, 'name_value'),
|
||||
array_keys($vars),
|
||||
array_values($vars));
|
||||
|
||||
foreach($properties as $property) {
|
||||
if(Services_JSON::isError($property)) {
|
||||
return $property;
|
||||
}
|
||||
}
|
||||
|
||||
return '{' . join(',', $properties) . '}';
|
||||
|
||||
default:
|
||||
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
|
||||
? 'null'
|
||||
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* array-walking function for use in generating JSON-formatted name-value pairs
|
||||
*
|
||||
* @param string $name name of key to use
|
||||
* @param mixed $value reference to an array element to be encoded
|
||||
*
|
||||
* @return string JSON-formatted name-value pair, like '"name":value'
|
||||
* @access private
|
||||
*/
|
||||
function name_value($name, $value)
|
||||
{
|
||||
$encoded_value = $this->encode($value);
|
||||
|
||||
if(Services_JSON::isError($encoded_value)) {
|
||||
return $encoded_value;
|
||||
}
|
||||
|
||||
return $this->encode((string)$name) . ':' . $encoded_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* reduce a string by removing leading and trailing comments and whitespace
|
||||
*
|
||||
* @param $str string string value to strip of comments and whitespace
|
||||
*
|
||||
* @return string string value stripped of comments and whitespace
|
||||
* @access private
|
||||
*/
|
||||
function reduce_string($str)
|
||||
{
|
||||
$str = preg_replace(array(
|
||||
|
||||
// eliminate single line comments in '// ...' form
|
||||
'#^\s*//(.+)$#m',
|
||||
|
||||
// eliminate multi-line comments in '/* ... */' form, at start of string
|
||||
'#^\s*/\*(.+)\*/#Us',
|
||||
|
||||
// eliminate multi-line comments in '/* ... */' form, at end of string
|
||||
'#/\*(.+)\*/\s*$#Us'
|
||||
|
||||
), '', $str);
|
||||
|
||||
// eliminate extraneous space
|
||||
return trim($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* decodes a JSON string into appropriate variable
|
||||
*
|
||||
* @param string $str JSON-formatted string
|
||||
*
|
||||
* @return mixed number, boolean, string, array, or object
|
||||
* corresponding to given JSON input string.
|
||||
* See argument 1 to Services_JSON() above for object-output behavior.
|
||||
* Note that decode() always returns strings
|
||||
* in ASCII or UTF-8 format!
|
||||
* @access public
|
||||
*/
|
||||
function decode($str)
|
||||
{
|
||||
$str = $this->reduce_string($str);
|
||||
|
||||
switch (strtolower($str)) {
|
||||
case 'true':
|
||||
return true;
|
||||
|
||||
case 'false':
|
||||
return false;
|
||||
|
||||
case 'null':
|
||||
return null;
|
||||
|
||||
default:
|
||||
$m = array();
|
||||
|
||||
if (is_numeric($str)) {
|
||||
// Lookie-loo, it's a number
|
||||
|
||||
// This would work on its own, but I'm trying to be
|
||||
// good about returning integers where appropriate:
|
||||
// return (float)$str;
|
||||
|
||||
// Return float or int, as appropriate
|
||||
return ((float)$str == (integer)$str)
|
||||
? (integer)$str
|
||||
: (float)$str;
|
||||
|
||||
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
|
||||
// STRINGS RETURNED IN UTF-8 FORMAT
|
||||
$delim = substr($str, 0, 1);
|
||||
$chrs = substr($str, 1, -1);
|
||||
$utf8 = '';
|
||||
$strlen_chrs = strlen($chrs);
|
||||
|
||||
for ($c = 0; $c < $strlen_chrs; ++$c) {
|
||||
|
||||
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
||||
$ord_chrs_c = ord($chrs{$c});
|
||||
|
||||
switch (true) {
|
||||
case $substr_chrs_c_2 == '\b':
|
||||
$utf8 .= chr(0x08);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\t':
|
||||
$utf8 .= chr(0x09);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\n':
|
||||
$utf8 .= chr(0x0A);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\f':
|
||||
$utf8 .= chr(0x0C);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\r':
|
||||
$utf8 .= chr(0x0D);
|
||||
++$c;
|
||||
break;
|
||||
|
||||
case $substr_chrs_c_2 == '\\"':
|
||||
case $substr_chrs_c_2 == '\\\'':
|
||||
case $substr_chrs_c_2 == '\\\\':
|
||||
case $substr_chrs_c_2 == '\\/':
|
||||
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
|
||||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
|
||||
$utf8 .= $chrs{++$c};
|
||||
}
|
||||
break;
|
||||
|
||||
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
|
||||
// single, escaped unicode character
|
||||
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
|
||||
. chr(hexdec(substr($chrs, ($c + 4), 2)));
|
||||
$utf8 .= $this->utf162utf8($utf16);
|
||||
$c += 5;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
|
||||
$utf8 .= $chrs{$c};
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xE0) == 0xC0:
|
||||
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
||||
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 2);
|
||||
++$c;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xF0) == 0xE0:
|
||||
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 3);
|
||||
$c += 2;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xF8) == 0xF0:
|
||||
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 4);
|
||||
$c += 3;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xFC) == 0xF8:
|
||||
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 5);
|
||||
$c += 4;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xFE) == 0xFC:
|
||||
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 6);
|
||||
$c += 5;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $utf8;
|
||||
|
||||
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
|
||||
// array, or object notation
|
||||
|
||||
if ($str{0} == '[') {
|
||||
$stk = array(SERVICES_JSON_IN_ARR);
|
||||
$arr = array();
|
||||
} else {
|
||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
||||
$stk = array(SERVICES_JSON_IN_OBJ);
|
||||
$obj = array();
|
||||
} else {
|
||||
$stk = array(SERVICES_JSON_IN_OBJ);
|
||||
$obj = new stdClass();
|
||||
}
|
||||
}
|
||||
|
||||
array_push($stk, array('what' => SERVICES_JSON_SLICE,
|
||||
'where' => 0,
|
||||
'delim' => false));
|
||||
|
||||
$chrs = substr($str, 1, -1);
|
||||
$chrs = $this->reduce_string($chrs);
|
||||
|
||||
if ($chrs == '') {
|
||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
||||
return $arr;
|
||||
|
||||
} else {
|
||||
return $obj;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//print("\nparsing {$chrs}\n");
|
||||
|
||||
$strlen_chrs = strlen($chrs);
|
||||
|
||||
for ($c = 0; $c <= $strlen_chrs; ++$c) {
|
||||
|
||||
$top = end($stk);
|
||||
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
||||
|
||||
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
|
||||
// found a comma that is not inside a string, array, etc.,
|
||||
// OR we've reached the end of the character list
|
||||
$slice = substr($chrs, $top['where'], ($c - $top['where']));
|
||||
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
|
||||
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
||||
// we are in an array, so just push an element onto the stack
|
||||
array_push($arr, $this->decode($slice));
|
||||
|
||||
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
||||
// we are in an object, so figure
|
||||
// out the property name and set an
|
||||
// element in an associative array,
|
||||
// for now
|
||||
$parts = array();
|
||||
|
||||
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
||||
// "name":value pair
|
||||
$key = $this->decode($parts[1]);
|
||||
$val = $this->decode($parts[2]);
|
||||
|
||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
||||
$obj[$key] = $val;
|
||||
} else {
|
||||
$obj->$key = $val;
|
||||
}
|
||||
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
||||
// name:value pair, where name is unquoted
|
||||
$key = $parts[1];
|
||||
$val = $this->decode($parts[2]);
|
||||
|
||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
||||
$obj[$key] = $val;
|
||||
} else {
|
||||
$obj->$key = $val;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
|
||||
// found a quote, and we are not inside a string
|
||||
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
|
||||
//print("Found start of string at {$c}\n");
|
||||
|
||||
} elseif (($chrs{$c} == $top['delim']) &&
|
||||
($top['what'] == SERVICES_JSON_IN_STR) &&
|
||||
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
|
||||
// found a quote, we're in a string, and it's not escaped
|
||||
// we know that it's not escaped becase there is _not_ an
|
||||
// odd number of backslashes at the end of the string so far
|
||||
array_pop($stk);
|
||||
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
|
||||
|
||||
} elseif (($chrs{$c} == '[') &&
|
||||
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
||||
// found a left-bracket, and we are in an array, object, or slice
|
||||
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
|
||||
//print("Found start of array at {$c}\n");
|
||||
|
||||
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
|
||||
// found a right-bracket, and we're in an array
|
||||
array_pop($stk);
|
||||
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
} elseif (($chrs{$c} == '{') &&
|
||||
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
||||
// found a left-brace, and we are in an array, object, or slice
|
||||
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
|
||||
//print("Found start of object at {$c}\n");
|
||||
|
||||
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
|
||||
// found a right-brace, and we're in an object
|
||||
array_pop($stk);
|
||||
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
} elseif (($substr_chrs_c_2 == '/*') &&
|
||||
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
||||
// found a comment start, and we are in an array, object, or slice
|
||||
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
|
||||
$c++;
|
||||
//print("Found start of comment at {$c}\n");
|
||||
|
||||
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
|
||||
// found a comment end, and we're in one now
|
||||
array_pop($stk);
|
||||
$c++;
|
||||
|
||||
for ($i = $top['where']; $i <= $c; ++$i)
|
||||
$chrs = substr_replace($chrs, ' ', $i, 1);
|
||||
|
||||
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
||||
return $arr;
|
||||
|
||||
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
||||
return $obj;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Ultimately, this should just call PEAR::isError()
|
||||
*/
|
||||
function isError($data, $code = null)
|
||||
{
|
||||
if (class_exists('pear')) {
|
||||
return PEAR::isError($data, $code);
|
||||
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
|
||||
is_subclass_of($data, 'services_json_error'))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists('PEAR_Error')) {
|
||||
|
||||
class Services_JSON_Error extends PEAR_Error
|
||||
{
|
||||
function Services_JSON_Error($message = 'unknown error', $code = null,
|
||||
$mode = null, $options = null, $userinfo = null)
|
||||
{
|
||||
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/**
|
||||
* @todo Ultimately, this class shall be descended from PEAR_Error
|
||||
*/
|
||||
class Services_JSON_Error
|
||||
{
|
||||
function Services_JSON_Error($message = 'unknown error', $code = null,
|
||||
$mode = null, $options = null, $userinfo = null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function json_encode($var)
|
||||
{
|
||||
$JSON = new Services_JSON;
|
||||
return $JSON->encode($var);
|
||||
}
|
||||
|
||||
function json_decode($var)
|
||||
{
|
||||
$JSON = new Services_JSON;
|
||||
return $JSON->decode($var);
|
||||
}
|
||||
94
webroot/forum/inc/adminfunctions_templates.php
Normal file
94
webroot/forum/inc/adminfunctions_templates.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find and replace a string in a particular template through every template set.
|
||||
*
|
||||
* @param string $title The name of the template
|
||||
* @param string $find The regular expression to match in the template
|
||||
* @param string $replace The replacement string
|
||||
* @param int $autocreate Set to 1 to automatically create templates which do not exist for sets with SID > 0 (based off master) - defaults to 1
|
||||
* @param mixed $sid Template SID to modify, false for every SID > 0 and SID = -1
|
||||
* @param int $limit The maximum possible replacements for the regular expression
|
||||
* @return boolean true if updated one or more templates, false if not.
|
||||
*/
|
||||
|
||||
function find_replace_templatesets($title, $find, $replace, $autocreate=1, $sid=false, $limit=-1)
|
||||
{
|
||||
global $db, $mybb;
|
||||
|
||||
$return = false;
|
||||
$template_sets = array(-2, -1);
|
||||
|
||||
// Select all templates with that title (including global) if not working on a specific template set
|
||||
$sqlwhere = '>0 OR sid=-1';
|
||||
$sqlwhere2 = '>0';
|
||||
|
||||
// Otherwise select just templates from that specific set
|
||||
if($sid !== false)
|
||||
{
|
||||
$sid = (int)$sid;
|
||||
$sqlwhere2 = $sqlwhere = "=$sid";
|
||||
}
|
||||
|
||||
// Select all other modified templates with that title
|
||||
$query = $db->simple_select("templates", "tid, sid, template", "title = '".$db->escape_string($title)."' AND (sid{$sqlwhere})");
|
||||
while($template = $db->fetch_array($query))
|
||||
{
|
||||
// Keep track of which templates sets have a modified version of this template already
|
||||
$template_sets[] = $template['sid'];
|
||||
|
||||
// Update the template if there is a replacement term or a change
|
||||
$new_template = preg_replace($find, $replace, $template['template'], $limit);
|
||||
if($new_template == $template['template'])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// The template is a custom template. Replace as normal.
|
||||
$updated_template = array(
|
||||
"template" => $db->escape_string($new_template)
|
||||
);
|
||||
$db->update_query("templates", $updated_template, "tid='{$template['tid']}'");
|
||||
|
||||
$return = true;
|
||||
}
|
||||
|
||||
// Add any new templates if we need to and are allowed to
|
||||
if($autocreate != 0)
|
||||
{
|
||||
// Select our master template with that title
|
||||
$query = $db->simple_select("templates", "title, template", "title='".$db->escape_string($title)."' AND sid='-2'", array('limit' => 1));
|
||||
$master_template = $db->fetch_array($query);
|
||||
$master_template['new_template'] = preg_replace($find, $replace, $master_template['template'], $limit);
|
||||
|
||||
if($master_template['new_template'] != $master_template['template'])
|
||||
{
|
||||
// Update the rest of our template sets that are currently inheriting this template from our master set
|
||||
$query = $db->simple_select("templatesets", "sid", "sid NOT IN (".implode(',', $template_sets).") AND (sid{$sqlwhere2})");
|
||||
while($template = $db->fetch_array($query))
|
||||
{
|
||||
$insert_template = array(
|
||||
"title" => $db->escape_string($master_template['title']),
|
||||
"template" => $db->escape_string($master_template['new_template']),
|
||||
"sid" => $template['sid'],
|
||||
"version" => $mybb->version_code,
|
||||
"status" => '',
|
||||
"dateline" => TIME_NOW
|
||||
);
|
||||
$db->insert_query("templates", $insert_template);
|
||||
|
||||
$return = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
114
webroot/forum/inc/cachehandlers/apc.php
Normal file
114
webroot/forum/inc/cachehandlers/apc.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* APC Cache Handler
|
||||
*/
|
||||
class apcCacheHandler implements CacheHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Unique identifier representing this copy of MyBB
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $unique_id;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
if(!function_exists("apc_fetch"))
|
||||
{
|
||||
// Check if our DB engine is loaded
|
||||
if(!extension_loaded("apc"))
|
||||
{
|
||||
// Throw our super awesome cache loading error
|
||||
$mybb->trigger_generic_error("apc_load_error");
|
||||
die;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect and initialize this handler.
|
||||
*
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function connect()
|
||||
{
|
||||
// Set a unique identifier for all queries in case other forums on this server also use this cache handler
|
||||
$this->unique_id = md5(MYBB_ROOT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect and initialize this handler.
|
||||
*
|
||||
* @param string $name
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function fetch($name)
|
||||
{
|
||||
if(apc_exists($this->unique_id."_".$name))
|
||||
{
|
||||
$data = apc_fetch($this->unique_id."_".$name);
|
||||
return unserialize($data);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @param mixed $contents The data to write to the cache item
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function put($name, $contents)
|
||||
{
|
||||
$status = apc_store($this->unique_id."_".$name, serialize($contents));
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function delete($name)
|
||||
{
|
||||
return apc_delete($this->unique_id."_".$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the cache
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function disconnect()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function size_of($name='')
|
||||
{
|
||||
global $lang;
|
||||
|
||||
return $lang->na;
|
||||
}
|
||||
}
|
||||
126
webroot/forum/inc/cachehandlers/disk.php
Normal file
126
webroot/forum/inc/cachehandlers/disk.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Disk Cache Handler
|
||||
*/
|
||||
class diskCacheHandler implements CacheHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Connect and initialize this handler.
|
||||
*
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function connect()
|
||||
{
|
||||
if(!@is_writable(MYBB_ROOT."cache"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an item from the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return mixed Cache data if successful, false if failure
|
||||
*/
|
||||
function fetch($name)
|
||||
{
|
||||
if(!@file_exists(MYBB_ROOT."/cache/{$name}.php"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@include(MYBB_ROOT."/cache/{$name}.php");
|
||||
|
||||
// Return data
|
||||
return $$name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @param mixed $contents The data to write to the cache item
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function put($name, $contents)
|
||||
{
|
||||
global $mybb;
|
||||
if(!is_writable(MYBB_ROOT."cache"))
|
||||
{
|
||||
$mybb->trigger_generic_error("cache_no_write");
|
||||
return false;
|
||||
}
|
||||
|
||||
$cache_file = fopen(MYBB_ROOT."cache/{$name}.php", "w") or $mybb->trigger_generic_error("cache_no_write");
|
||||
flock($cache_file, LOCK_EX);
|
||||
$cache_contents = "<?php\ndeclare(encoding='UTF-8');\n\n/** MyBB Generated Cache - Do Not Alter\n * Cache Name: $name\n * Generated: ".gmdate("r")."\n*/\n\n";
|
||||
$cache_contents .= "\$$name = ".var_export($contents, true).";\n\n?>";
|
||||
fwrite($cache_file, $cache_contents);
|
||||
flock($cache_file, LOCK_UN);
|
||||
fclose($cache_file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function delete($name)
|
||||
{
|
||||
return @unlink(MYBB_ROOT."/cache/{$name}.php");
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the cache
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function disconnect()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the size of the disk cache
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return integer the size of the disk cache
|
||||
*/
|
||||
function size_of($name='')
|
||||
{
|
||||
if($name != '')
|
||||
{
|
||||
return @filesize(MYBB_ROOT."/cache/{$name}.php");
|
||||
}
|
||||
else
|
||||
{
|
||||
$total = 0;
|
||||
$dir = opendir(MYBB_ROOT."/cache");
|
||||
while(($file = readdir($dir)) !== false)
|
||||
{
|
||||
if($file == "." || $file == ".." || $file == ".svn" || !is_file(MYBB_ROOT."/cache/{$file}"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$total += filesize(MYBB_ROOT."/cache/{$file}");
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
}
|
||||
}
|
||||
116
webroot/forum/inc/cachehandlers/eaccelerator.php
Normal file
116
webroot/forum/inc/cachehandlers/eaccelerator.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* eAccelerator Cache Handler
|
||||
*/
|
||||
class eacceleratorCacheHandler implements CacheHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Unique identifier representing this copy of MyBB
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $unique_id;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
if(!function_exists("eaccelerator_get"))
|
||||
{
|
||||
// Check if our DB engine is loaded
|
||||
if(!extension_loaded("Eaccelerator"))
|
||||
{
|
||||
// Throw our super awesome cache loading error
|
||||
$mybb->trigger_generic_error("eaccelerator_load_error");
|
||||
die;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect and initialize this handler.
|
||||
*
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function connect()
|
||||
{
|
||||
// Set a unique identifier for all queries in case other forums on this server also use this cache handler
|
||||
$this->unique_id = md5(MYBB_ROOT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an item from the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return mixed Cache data if successful, false if failure
|
||||
*/
|
||||
function fetch($name)
|
||||
{
|
||||
$data = eaccelerator_get($this->unique_id."_".$name);
|
||||
if($data === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return unserialize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @param mixed $contents The data to write to the cache item
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function put($name, $contents)
|
||||
{
|
||||
eaccelerator_lock($this->unique_id."_".$name);
|
||||
$status = eaccelerator_put($this->unique_id."_".$name, serialize($contents));
|
||||
eaccelerator_unlock($this->unique_id."_".$name);
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function delete($name)
|
||||
{
|
||||
return eaccelerator_rm($this->unique_id."_".$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the cache
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function disconnect()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function size_of($name='')
|
||||
{
|
||||
global $lang;
|
||||
|
||||
return $lang->na;
|
||||
}
|
||||
}
|
||||
8
webroot/forum/inc/cachehandlers/index.html
Normal file
8
webroot/forum/inc/cachehandlers/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
61
webroot/forum/inc/cachehandlers/interface.php
Normal file
61
webroot/forum/inc/cachehandlers/interface.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Cache Handler Interface
|
||||
*/
|
||||
interface CacheHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Connect and initialize this handler.
|
||||
*
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function connect();
|
||||
|
||||
/**
|
||||
* Connect and initialize this handler.
|
||||
*
|
||||
* @param string $name
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function fetch($name);
|
||||
|
||||
/**
|
||||
* Write an item to the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @param mixed $contents The data to write to the cache item
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function put($name, $contents);
|
||||
|
||||
/**
|
||||
* Delete a cache
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function delete($name);
|
||||
|
||||
/**
|
||||
* Disconnect from the cache
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function disconnect();
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function size_of($name='');
|
||||
}
|
||||
157
webroot/forum/inc/cachehandlers/memcache.php
Normal file
157
webroot/forum/inc/cachehandlers/memcache.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Memcache Cache Handler
|
||||
*/
|
||||
class memcacheCacheHandler implements CacheHandlerInterface
|
||||
{
|
||||
/**
|
||||
* The memcache server resource
|
||||
*
|
||||
* @var Memcache
|
||||
*/
|
||||
public $memcache;
|
||||
|
||||
/**
|
||||
* Unique identifier representing this copy of MyBB
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $unique_id;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
if(!function_exists("memcache_connect"))
|
||||
{
|
||||
// Check if our DB engine is loaded
|
||||
if(!extension_loaded("Memcache"))
|
||||
{
|
||||
// Throw our super awesome cache loading error
|
||||
$mybb->trigger_generic_error("memcache_load_error");
|
||||
die;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect and initialize this handler.
|
||||
*
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function connect()
|
||||
{
|
||||
global $mybb, $error_handler;
|
||||
|
||||
$this->memcache = new Memcache;
|
||||
|
||||
if($mybb->config['memcache']['host'])
|
||||
{
|
||||
$mybb->config['memcache'][0] = $mybb->config['memcache'];
|
||||
unset($mybb->config['memcache']['host']);
|
||||
unset($mybb->config['memcache']['port']);
|
||||
}
|
||||
|
||||
foreach($mybb->config['memcache'] as $memcache)
|
||||
{
|
||||
if(!$memcache['host'])
|
||||
{
|
||||
$message = "Please configure the memcache settings in inc/config.php before attempting to use this cache handler";
|
||||
$error_handler->trigger($message, MYBB_CACHEHANDLER_LOAD_ERROR);
|
||||
die;
|
||||
}
|
||||
|
||||
if(!isset($memcache['port']))
|
||||
{
|
||||
$memcache['port'] = "11211";
|
||||
}
|
||||
|
||||
$this->memcache->addServer($memcache['host'], $memcache['port']);
|
||||
|
||||
if(!$this->memcache)
|
||||
{
|
||||
$message = "Unable to connect to the memcache server on {$memcache['memcache_host']}:{$memcache['memcache_port']}. Are you sure it is running?";
|
||||
$error_handler->trigger($message, MYBB_CACHEHANDLER_LOAD_ERROR);
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
// Set a unique identifier for all queries in case other forums are using the same memcache server
|
||||
$this->unique_id = md5(MYBB_ROOT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an item from the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return mixed Cache data if successful, false if failure
|
||||
*/
|
||||
function fetch($name)
|
||||
{
|
||||
$data = $this->memcache->get($this->unique_id."_".$name);
|
||||
|
||||
if($data === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @param mixed $contents The data to write to the cache item
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function put($name, $contents)
|
||||
{
|
||||
return $this->memcache->set($this->unique_id."_".$name, $contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function delete($name)
|
||||
{
|
||||
return $this->memcache->delete($this->unique_id."_".$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the cache
|
||||
*/
|
||||
function disconnect()
|
||||
{
|
||||
@$this->memcache->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function size_of($name='')
|
||||
{
|
||||
global $lang;
|
||||
|
||||
return $lang->na;
|
||||
}
|
||||
}
|
||||
|
||||
157
webroot/forum/inc/cachehandlers/memcached.php
Normal file
157
webroot/forum/inc/cachehandlers/memcached.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Memcached Cache Handler
|
||||
*/
|
||||
class memcachedCacheHandler implements CacheHandlerInterface
|
||||
{
|
||||
/**
|
||||
* The memcached server resource
|
||||
*
|
||||
* @var Memcached
|
||||
*/
|
||||
public $memcached;
|
||||
|
||||
/**
|
||||
* Unique identifier representing this copy of MyBB
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $unique_id;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
if(!function_exists("memcached_connect"))
|
||||
{
|
||||
// Check if our Memcached extension is loaded
|
||||
if(!extension_loaded("Memcached"))
|
||||
{
|
||||
// Throw our super awesome cache loading error
|
||||
$mybb->trigger_generic_error("memcached_load_error");
|
||||
die;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect and initialize this handler.
|
||||
*
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function connect()
|
||||
{
|
||||
global $mybb, $error_handler;
|
||||
|
||||
$this->memcached = new Memcached;
|
||||
|
||||
if($mybb->config['memcache']['host'])
|
||||
{
|
||||
$mybb->config['memcache'][0] = $mybb->config['memcache'];
|
||||
unset($mybb->config['memcache']['host']);
|
||||
unset($mybb->config['memcache']['port']);
|
||||
}
|
||||
|
||||
foreach($mybb->config['memcache'] as $memcached)
|
||||
{
|
||||
if(!$memcached['host'])
|
||||
{
|
||||
$message = "Please configure the memcache settings in inc/config.php before attempting to use this cache handler";
|
||||
$error_handler->trigger($message, MYBB_CACHEHANDLER_LOAD_ERROR);
|
||||
die;
|
||||
}
|
||||
|
||||
if(!isset($memcached['port']))
|
||||
{
|
||||
$memcached['port'] = "11211";
|
||||
}
|
||||
|
||||
$this->memcached->addServer($memcached['host'], $memcached['port']);
|
||||
|
||||
if(!$this->memcached)
|
||||
{
|
||||
$message = "Unable to connect to the memcached server on {$memcached['memcache_host']}:{$memcached['memcache_port']}. Are you sure it is running?";
|
||||
$error_handler->trigger($message, MYBB_CACHEHANDLER_LOAD_ERROR);
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
// Set a unique identifier for all queries in case other forums are using the same memcache server
|
||||
$this->unique_id = md5(MYBB_ROOT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an item from the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return mixed Cache data if successful, false if failure
|
||||
*/
|
||||
function fetch($name)
|
||||
{
|
||||
$data = $this->memcached->get($this->unique_id."_".$name);
|
||||
|
||||
if($data === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @param mixed $contents The data to write to the cache item
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function put($name, $contents)
|
||||
{
|
||||
return $this->memcached->set($this->unique_id."_".$name, $contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function delete($name)
|
||||
{
|
||||
return $this->memcached->delete($this->unique_id."_".$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the cache
|
||||
*/
|
||||
function disconnect()
|
||||
{
|
||||
@$this->memcached->quit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function size_of($name='')
|
||||
{
|
||||
global $lang;
|
||||
|
||||
return $lang->na;
|
||||
}
|
||||
}
|
||||
|
||||
111
webroot/forum/inc/cachehandlers/xcache.php
Normal file
111
webroot/forum/inc/cachehandlers/xcache.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Xcache Cache Handler
|
||||
*/
|
||||
class xcacheCacheHandler implements CacheHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Unique identifier representing this copy of MyBB
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $unique_id;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
if(!function_exists("xcache_get"))
|
||||
{
|
||||
// Check if our DB engine is loaded
|
||||
if(!extension_loaded("XCache"))
|
||||
{
|
||||
// Throw our super awesome cache loading error
|
||||
$mybb->trigger_generic_error("xcache_load_error");
|
||||
die;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect and initialize this handler.
|
||||
*
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function connect()
|
||||
{
|
||||
// Set a unique identifier for all queries in case other forums on this server also use this cache handler
|
||||
$this->unique_id = md5(MYBB_ROOT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an item from the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return mixed Cache data if successful, false if failure
|
||||
*/
|
||||
function fetch($name)
|
||||
{
|
||||
if(!xcache_isset($this->unique_id."_".$name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return xcache_get($this->unique_id."_".$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache.
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @param mixed $contents The data to write to the cache item
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function put($name, $contents)
|
||||
{
|
||||
return xcache_set($this->unique_id."_".$name, $contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache
|
||||
*
|
||||
* @param string $name The name of the cache
|
||||
* @return boolean True on success, false on failure
|
||||
*/
|
||||
function delete($name)
|
||||
{
|
||||
return xcache_set($this->unique_id."_".$name, "", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the cache
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function disconnect()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function size_of($name='')
|
||||
{
|
||||
global $lang;
|
||||
|
||||
return $lang->na;
|
||||
}
|
||||
}
|
||||
BIN
webroot/forum/inc/captcha_fonts/MINYN___.ttf
Normal file
BIN
webroot/forum/inc/captcha_fonts/MINYN___.ttf
Normal file
Binary file not shown.
BIN
webroot/forum/inc/captcha_fonts/edmunds.ttf
Normal file
BIN
webroot/forum/inc/captcha_fonts/edmunds.ttf
Normal file
Binary file not shown.
8
webroot/forum/inc/captcha_fonts/index.html
Normal file
8
webroot/forum/inc/captcha_fonts/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
253
webroot/forum/inc/captcha_fonts/read_me.html
Normal file
253
webroot/forum/inc/captcha_fonts/read_me.html
Normal file
@@ -0,0 +1,253 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>
|
||||
Larabie Fonts "read me" file, license and FAQ
|
||||
</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
<meta name="keywords" content=
|
||||
"typodermic,typo dermic,fonts,Larabie,Larabie Fonts,fontd,fotn,fnots,fons,fots,fnts,font,truetype,typefaces,typeface,logo,ttf,opentype,larbie,laribie,larby,larabee,lairby,larrabie,larraby,laraby,typography,Type1,postscript,macintosh,windows,design,lettering,type" />
|
||||
</head>
|
||||
<body>
|
||||
<h3>
|
||||
LARABIE FONTS “README.TXT”
|
||||
</h3>
|
||||
<p>
|
||||
All Larabie Fonts in this file are free to use for personal and/or commercial purposes. No
|
||||
payment is necessary to use these fonts for personal or commercial use. For Software Products
|
||||
who want to include Larabie Fonts see the License Agreement below. You can add this font to a
|
||||
website but do not combine fonts into a single archive or alter them in any way.
|
||||
</p>
|
||||
<p>
|
||||
All Larabie Fonts are free for commercial use but a sample of your product would be
|
||||
gratefully appreciated so I can see how the font looks in use. Contact <a href=
|
||||
"http://www.larabiefonts.com/donation.html">www.larabiefonts.com/donation.html</a> for
|
||||
mailing information.
|
||||
</p>
|
||||
<p>
|
||||
Some Larabie Fonts have enhanced and expanded families available for sale at <a href=
|
||||
"http://www.typodermic.com">www.typodermic.com</a>.
|
||||
</p>
|
||||
<p>
|
||||
If you'd like to make a voluntary donation to Larabie Fonts for the use of the free fonts in
|
||||
any amount please go to <a href=
|
||||
"http://www.larabiefonts.com/donation.html">www.larabiefonts.com/donation.html</a>
|
||||
</p>
|
||||
<p>
|
||||
I accept CDs, magazines, t-shirts, a sample of your merchandise or anything featuring Larabie
|
||||
Fonts. Please remember to list your item as a ‘gift’ on the customs form or I will have to
|
||||
pay import duties and taxes on the item. Mailing information is provided at the link above.
|
||||
</p>
|
||||
<p>
|
||||
Font installation help is available at <a href=
|
||||
"http://www.larabiefonts.com/help.html">www.larabiefonts.com/help.html</a>
|
||||
</p>
|
||||
<h3>
|
||||
LARABIE FONTS FREQUENTLY ASKED QUESTIONS
|
||||
</h3>
|
||||
<ul>
|
||||
<li>Q: How do use these fonts in my favourite software?
|
||||
</li>
|
||||
<li>A: In Windows, you take the fonts out of the ZIP archive and place them in your fonts
|
||||
folder which can be found in your Control Panel. The next time you run your software, the
|
||||
font will be available. For example: If you install a new font, the next time you run
|
||||
Microsoft Word, that font will be available in the menu under Format / Font. For anything
|
||||
more complicated, or Mac installation, visit <a href="http://www.larabiefonts.com/help.html">
|
||||
www.larabiefonts.com/help.html</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: How can I use this font in <a href="http://www.aol.com/aim/">AOL Instant
|
||||
Messenger</a>, <a href="http://messenger.msn.com/">MSN Messenger</a>, <a href=
|
||||
"http://www.microsoft.com/office/outlook/">Outlook</a>, <a href=
|
||||
"http://www.microsoft.com/office/outlook/">Outlook Express</a>, <a href=
|
||||
"http://www.eudora.com/">Euodora</a> or any other email software?
|
||||
</li>
|
||||
<li>A: At the time of this writing (Feb 2004) you can’t. After installing one of my fonts,
|
||||
you may be able to select it in the above applications but the person at the other end won’t
|
||||
see that same thing unless they have the font installed. If you really want to use my fonts
|
||||
in these applications, make sure the people at the other end have the same fonts installed.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: How can I use these fonts on a web page?
|
||||
</li>
|
||||
<li>A: If you’re creating a web page using Flash, it’s easy. Consult your Flash manual. If
|
||||
you’re using <a href="http://www.adobe.com/products/acrobat/">Acrobat</a>, make sure the font
|
||||
embedding settings are turned on. Consult your Acrobat manual. For anything else there are
|
||||
limitations: If you want to use one of my fonts as your main, text font you’re pretty much
|
||||
out of luck unless you explore a font embedding tool such as <a href=
|
||||
"http://www.microsoft.com/typography/web/embedding/weft/">WEFT</a> but I don’t recommend it.
|
||||
To use my fonts as headings or titles, use image creation software such as <a href=
|
||||
"http://www.gimp.org/">The Gimp</a>, <a href=
|
||||
"http://www.adobe.com/products/photoshop/">Photoshop</a>, <a href=
|
||||
"http://www.jasc.com/">Paint Shop Pro</a>, <a href=
|
||||
"http://www.google.com/search?q=pixia">Pixia</a> etc. Save the images as GIF files and place
|
||||
them on your web page. There’s a lot more to it than can be explained here but there are
|
||||
countless books available on web page design.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: How can I make these fonts bigger?
|
||||
</li>
|
||||
<li>A: All my fonts are infinitely scalable; the limitations are in your software. A common
|
||||
problem is scaling fonts in Microsoft Word. If you choose Format / Font you can type in any
|
||||
number you like under “size”.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: Are these fonts really free?
|
||||
</li>
|
||||
<li>A: Yes they are. Some fonts such as <a href=
|
||||
"http://www.typodermic.com/fonts/19.html">Neuropol</a> have expanded font families available
|
||||
for sale at <a href="http://www.typodermic.com">www.typodermic.com</a> but the version you
|
||||
downloaded at Larabie Fonts is free.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: Your licence agreement states that the fonts can’t be altered. Does that mean I can’t
|
||||
mess around with your fonts in Photoshop/Illustrator/Publisher etc?
|
||||
</li>
|
||||
<li>A: Those license restrictions refer to altering the actual fonts themselves, not what you
|
||||
make with them. As long as you don’t alter the font files in font creation software such as
|
||||
FontLab or Fontographer you’re free to create anything you like with them.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: Can I use your fonts in a logo?
|
||||
</li>
|
||||
<li>A: Yes. But check with a lawyer if you’re not sure. It’s okay with me if you use it but
|
||||
do so at your own risk.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: Can I send you a sample of the nifty thing I created with your fonts?
|
||||
</li>
|
||||
<li>A: Of course. Check <a href=
|
||||
"http://www.larabiefonts.com/donation.html">www.larabiefonts.com/donation.html</a> for my
|
||||
current email or mailing address.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: Can you make a custom font for me?
|
||||
</li>
|
||||
<li>A: Possibly. Check <a href=
|
||||
"http://typodermic.com/custom.html">typodermic.com/custom.html</a> for details. Keep in mind
|
||||
that making fonts is my full-time job so no freebies.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: I want to sell software that includes you font files.
|
||||
</li>
|
||||
<li>A: Contact me first at <a href=
|
||||
"http://www.larabiefonts.com/email.html">www.larabiefonts.com/email.html</a>.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: I want to sell rubber stamp alphabets, alphabet punches or stencil alphabets using
|
||||
your font designs.
|
||||
</li>
|
||||
<li>A: Contact me first at <a href=
|
||||
"http://www.larabiefonts.com/email.html">www.larabiefonts.com/email.html</a>.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: My software won’t let me embed one of your fonts.
|
||||
</li>
|
||||
<li>A: You may have an old version of one of my fonts. Uninstall it and install a current
|
||||
version on Larabie Fonts.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Q: Can you help me find a font?
|
||||
</li>
|
||||
<li>A: I really don’t have the time but if you send a donation, I can give it a try. If not.
|
||||
post your question on my font forum: <a href=
|
||||
"http://www.larabiefonts.com/info.html">www.larabiefonts.com/info.html</a>.
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
LARABIE FONTS END-USER LICENSE AGREEMENT FOR SOFTWARE PRODUCTS
|
||||
</h3>
|
||||
<h4>
|
||||
SOFTWARE PRODUCT LICENSE
|
||||
</h4>
|
||||
<p>
|
||||
The SOFTWARE PRODUCT is protected by copyright laws and International copyright treaties, as
|
||||
well as other intellectual property laws and treaties. The SOFTWARE PRODUCT is licensed, not
|
||||
sold.
|
||||
</p>
|
||||
<h5>
|
||||
1. GRANT OF LICENSE. This document grants you the following rights:
|
||||
</h5>
|
||||
<p>
|
||||
- Installation and Use. You may install and use an unlimited number of copies of the SOFTWARE
|
||||
PRODUCT. You may copy and distribute unlimited copies of the SOFTWARE PRODUCT as you receive
|
||||
them, in any medium, provided that you publish on each copy an appropriate copyright notice.
|
||||
Keep intact all the notices that refer to this License and give any other recipients of the
|
||||
fonts a copy of this License along with the fonts.
|
||||
</p>
|
||||
<h5>
|
||||
2. DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS.
|
||||
</h5>
|
||||
<p>
|
||||
- You may modify your copy or copies of the SOFTWARE PRODUCT or any portion of it, provided
|
||||
that you also meet all of these rules:
|
||||
</p>
|
||||
<p>
|
||||
a) Do not alter in any way alphanumeric characters (A-Z, a-z, 1-9) contained in the font. An
|
||||
exception is converting between formats, here is allowed the nominal distortion that occurs
|
||||
during conversion from second order to third order quadratic curves (TrueType to Postscript)
|
||||
and vice versa.
|
||||
</p>
|
||||
<p>
|
||||
b) Extra characters may be added; here it is allowed to use curves (shapes) from alphanumeric
|
||||
characters in fonts under same license.
|
||||
</p>
|
||||
<p>
|
||||
c) It is allowed to modify and remove analpahbetics (punctuation, special characters,
|
||||
ligatures and symbols).
|
||||
</p>
|
||||
<p>
|
||||
d) The original font name must be retained but can be augmented. (ie. a Font named Blue
|
||||
Highway can be renamed Blue Highway Cyrillic or Blue Highway ANSI, etc.)
|
||||
</p>
|
||||
<p>
|
||||
e) Character mapping may be altered.
|
||||
</p>
|
||||
<p>
|
||||
f) If the kerning information is altered or discarded it must be stated in the user notes or
|
||||
documentation.
|
||||
</p>
|
||||
<p>
|
||||
g) All modifications must be released under this license.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>LIMITED WARRANTY NO WARRANTIES. Larabie Fonts expressly disclaims any warranty for the
|
||||
SOFTWARE PRODUCT. The SOFTWARE PRODUCT and any related documentation is provided "as is"
|
||||
without warranty of any kind, either express or implied, including, without limitation, the
|
||||
implied warranties or merchantability, fitness for a particular purpose, or non-infringement.
|
||||
The entire risk arising out of use or performance of the SOFTWARE PRODUCT remains with you.
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
NO LIABILITY FOR CONSEQUENTIAL DAMAGES. In no event shall Larabie Fonts be liable for any
|
||||
damages whatsoever (including, without limitation, damages for loss of business profits,
|
||||
business interruption, loss of business information, or any other pecuniary loss) arising out
|
||||
of the use of or inability to use this product, even if Larabie Fonts has been advised of the
|
||||
possibility of such damages.
|
||||
</p>
|
||||
<h5>
|
||||
3. MISCELLANEOUS
|
||||
</h5>
|
||||
<p>
|
||||
Should you have any questions concerning this document, or if you desire to contact Larabie
|
||||
Fonts for any reason, please email <a href=
|
||||
"http://www.larabiefonts.com/email.html">www.larabiefonts.com/email.html</a>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
390
webroot/forum/inc/class_captcha.php
Normal file
390
webroot/forum/inc/class_captcha.php
Normal file
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
* This class is based from reCAPTCHA's PHP library, adapted for use in MyBB.
|
||||
*
|
||||
* Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
|
||||
* AUTHORS:
|
||||
* Mike Crawford
|
||||
* Ben Maurer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
class captcha
|
||||
{
|
||||
/**
|
||||
* Type of CAPTCHA.
|
||||
*
|
||||
* 1 = Default CAPTCHA
|
||||
* 2 = reCAPTCHA
|
||||
* 4 = NoCATPCHA reCAPTCHA
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $type = 0;
|
||||
|
||||
/**
|
||||
* The template to display the CAPTCHA in
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $captcha_template = '';
|
||||
|
||||
/**
|
||||
* CAPTCHA Server URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $server = '';
|
||||
|
||||
/**
|
||||
* CAPTCHA Verify Server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $verify_server = '';
|
||||
|
||||
/**
|
||||
* HTML of the built CAPTCHA
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $html = '';
|
||||
|
||||
/**
|
||||
* The errors that occurred when handling data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* @param bool $build
|
||||
* @param string $template
|
||||
*/
|
||||
function __construct($build = false, $template = "")
|
||||
{
|
||||
global $mybb, $plugins;
|
||||
|
||||
$this->type = $mybb->settings['captchaimage'];
|
||||
|
||||
$args = array(
|
||||
'this' => &$this,
|
||||
'build' => &$build,
|
||||
'template' => &$template,
|
||||
);
|
||||
|
||||
$plugins->run_hooks('captcha_build_start', $args);
|
||||
|
||||
// Prepare the build template
|
||||
if($template)
|
||||
{
|
||||
$this->captcha_template = $template;
|
||||
|
||||
if($this->type == 4)
|
||||
{
|
||||
$this->captcha_template .= "_nocaptcha";
|
||||
}
|
||||
elseif($this->type == 5)
|
||||
{
|
||||
$this->captcha_template .= "_recaptcha_invisible";
|
||||
}
|
||||
}
|
||||
|
||||
// Work on which CAPTCHA we've got installed
|
||||
if(in_array($this->type, array(4, 5)) && $mybb->settings['captchapublickey'] && $mybb->settings['captchaprivatekey'])
|
||||
{
|
||||
// We want to use noCAPTCHA or reCAPTCHA invisible, set the server options
|
||||
$this->server = "//www.google.com/recaptcha/api.js";
|
||||
$this->verify_server = "https://www.google.com/recaptcha/api/siteverify";
|
||||
|
||||
if($build == true)
|
||||
{
|
||||
$this->build_recaptcha();
|
||||
}
|
||||
}
|
||||
elseif($this->type == 1)
|
||||
{
|
||||
if(!function_exists("imagecreatefrompng"))
|
||||
{
|
||||
// We want to use the default CAPTCHA, but it's not installed
|
||||
return;
|
||||
}
|
||||
elseif($build == true)
|
||||
{
|
||||
$this->build_captcha();
|
||||
}
|
||||
}
|
||||
|
||||
$plugins->run_hooks('captcha_build_end', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $return Not used
|
||||
*/
|
||||
function build_captcha($return = false)
|
||||
{
|
||||
global $db, $lang, $templates, $theme, $mybb;
|
||||
|
||||
// This will build a MyBB CAPTCHA
|
||||
$randomstr = random_str(5);
|
||||
$imagehash = md5(random_str(12));
|
||||
|
||||
$insert_array = array(
|
||||
"imagehash" => $imagehash,
|
||||
"imagestring" => $randomstr,
|
||||
"dateline" => TIME_NOW
|
||||
);
|
||||
|
||||
$db->insert_query("captcha", $insert_array);
|
||||
eval("\$this->html = \"".$templates->get($this->captcha_template)."\";");
|
||||
//eval("\$this->html = \"".$templates->get("member_register_regimage")."\";");
|
||||
}
|
||||
|
||||
function build_recaptcha()
|
||||
{
|
||||
global $lang, $mybb, $templates;
|
||||
|
||||
// This will build a reCAPTCHA
|
||||
$server = $this->server;
|
||||
$public_key = $mybb->settings['captchapublickey'];
|
||||
|
||||
eval("\$this->html = \"".$templates->get($this->captcha_template, 1, 0)."\";");
|
||||
//eval("\$this->html = \"".$templates->get("member_register_regimage_recaptcha")."\";");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function build_hidden_captcha()
|
||||
{
|
||||
global $db, $mybb, $templates;
|
||||
|
||||
$field = array();
|
||||
|
||||
if($this->type == 1)
|
||||
{
|
||||
// Names
|
||||
$hash = "imagehash";
|
||||
$string = "imagestring";
|
||||
|
||||
// Values
|
||||
$field['hash'] = $db->escape_string($mybb->input['imagehash']);
|
||||
$field['string'] = $db->escape_string($mybb->input['imagestring']);
|
||||
}
|
||||
elseif($this->type == 3)
|
||||
{
|
||||
// Are You a Human can't be built as a hidden captcha
|
||||
return '';
|
||||
}
|
||||
|
||||
eval("\$this->html = \"".$templates->get("post_captcha_hidden")."\";");
|
||||
return $this->html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function validate_captcha()
|
||||
{
|
||||
global $db, $lang, $mybb, $session, $plugins;
|
||||
|
||||
$plugins->run_hooks('captcha_validate_start', $this);
|
||||
|
||||
if($this->type == 1)
|
||||
{
|
||||
// We have a normal CAPTCHA to handle
|
||||
$imagehash = $db->escape_string($mybb->input['imagehash']);
|
||||
$imagestring = $db->escape_string(my_strtolower($mybb->input['imagestring']));
|
||||
|
||||
switch($db->type)
|
||||
{
|
||||
case 'mysql':
|
||||
case 'mysqli':
|
||||
$field = 'imagestring';
|
||||
break;
|
||||
default:
|
||||
$field = 'LOWER(imagestring)';
|
||||
break;
|
||||
}
|
||||
|
||||
$query = $db->simple_select("captcha", "*", "imagehash = '{$imagehash}' AND {$field} = '{$imagestring}'");
|
||||
$imgcheck = $db->fetch_array($query);
|
||||
|
||||
if(!$imgcheck)
|
||||
{
|
||||
$this->set_error($lang->invalid_captcha_verify);
|
||||
$db->delete_query("captcha", "imagehash = '{$imagehash}'");
|
||||
}
|
||||
}
|
||||
elseif(in_array($this->type, array(4, 5)))
|
||||
{
|
||||
$response = $mybb->input['g-recaptcha-response'];
|
||||
if(!$response || strlen($response) == 0)
|
||||
{
|
||||
$this->set_error($lang->invalid_nocaptcha);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have a noCAPTCHA or reCAPTCHA invisible to handle
|
||||
// Contact Google and see if our reCAPTCHA was successful
|
||||
$response = fetch_remote_file($this->verify_server, array(
|
||||
'secret' => $mybb->settings['captchaprivatekey'],
|
||||
'remoteip' => $session->ipaddress,
|
||||
'response' => $response
|
||||
));
|
||||
|
||||
if($response == false)
|
||||
{
|
||||
$this->set_error($lang->invalid_nocaptcha_transmit);
|
||||
}
|
||||
else
|
||||
{
|
||||
$answer = json_decode($response, true);
|
||||
|
||||
if($answer['success'] != 'true')
|
||||
{
|
||||
// We got it wrong! Oh no...
|
||||
$this->set_error($lang->invalid_nocaptcha);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$plugins->run_hooks('captcha_validate_end', $this);
|
||||
|
||||
if(count($this->errors) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function invalidate_captcha()
|
||||
{
|
||||
global $db, $mybb, $plugins;
|
||||
|
||||
if($this->type == 1)
|
||||
{
|
||||
// We have a normal CAPTCHA to handle
|
||||
$imagehash = $db->escape_string($mybb->input['imagehash']);
|
||||
if($imagehash)
|
||||
{
|
||||
$db->delete_query("captcha", "imagehash = '{$imagehash}'");
|
||||
}
|
||||
}
|
||||
// Not necessary for reCAPTCHA or Are You a Human
|
||||
|
||||
$plugins->run_hooks('captcha_invalidate_end', $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error to the error array.
|
||||
*
|
||||
* @param string $error
|
||||
* @param string $data
|
||||
*/
|
||||
function set_error($error, $data='')
|
||||
{
|
||||
$this->errors[$error] = array(
|
||||
"error_code" => $error,
|
||||
"data" => $data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error(s) that occurred when handling data
|
||||
* in a format that MyBB can handle.
|
||||
*
|
||||
* @return array An array of errors in a MyBB format.
|
||||
*/
|
||||
function get_errors()
|
||||
{
|
||||
global $lang;
|
||||
|
||||
$errors = array();
|
||||
foreach($this->errors as $error)
|
||||
{
|
||||
$lang_string = $error['error_code'];
|
||||
|
||||
if(!$lang_string)
|
||||
{
|
||||
if($lang->invalid_captcha_verify)
|
||||
{
|
||||
$lang_string = 'invalid_captcha_verify';
|
||||
}
|
||||
else
|
||||
{
|
||||
$lang_string = 'unknown_error';
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($lang->$lang_string))
|
||||
{
|
||||
$errors[] = $error['error_code'];
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!empty($error['data']) && !is_array($error['data']))
|
||||
{
|
||||
$error['data'] = array($error['data']);
|
||||
}
|
||||
|
||||
if(is_array($error['data']))
|
||||
{
|
||||
array_unshift($error['data'], $lang->$lang_string);
|
||||
$errors[] = call_user_func_array(array($lang, "sprintf"), $error['data']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$errors[] = $lang->$lang_string;
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _qsencode($data)
|
||||
{
|
||||
$req = '';
|
||||
foreach($data as $key => $value)
|
||||
{
|
||||
$req .= $key.'='.urlencode(stripslashes($value)).'&';
|
||||
}
|
||||
|
||||
$req = substr($req, 0, (strlen($req) - 1));
|
||||
|
||||
return $req;
|
||||
}
|
||||
}
|
||||
627
webroot/forum/inc/class_core.php
Normal file
627
webroot/forum/inc/class_core.php
Normal file
@@ -0,0 +1,627 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
class MyBB {
|
||||
/**
|
||||
* The friendly version number of MyBB we're running.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $version = "1.8.21";
|
||||
|
||||
/**
|
||||
* The version code of MyBB we're running.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $version_code = 1821;
|
||||
|
||||
/**
|
||||
* The current working directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $cwd = ".";
|
||||
|
||||
/**
|
||||
* Input variables received from the outer world.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input = array();
|
||||
|
||||
/**
|
||||
* Cookie variables received from the outer world.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $cookies = array();
|
||||
|
||||
/**
|
||||
* Information about the current user.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $user = array();
|
||||
|
||||
/**
|
||||
* Information about the current usergroup.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $usergroup = array();
|
||||
|
||||
/**
|
||||
* MyBB settings.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $settings = array();
|
||||
|
||||
/**
|
||||
* Whether or not magic quotes are enabled.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $magicquotes = 0;
|
||||
|
||||
/**
|
||||
* Whether or not MyBB supports SEO URLs
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $seo_support = false;
|
||||
|
||||
/**
|
||||
* MyBB configuration.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $config = array();
|
||||
|
||||
/**
|
||||
* The request method that called this page.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $request_method = "";
|
||||
|
||||
/**
|
||||
* Whether or not PHP's safe_mode is enabled
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $safemode = false;
|
||||
|
||||
/**
|
||||
* Loads templates directly from the master theme and disables the installer locked error
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $dev_mode = false;
|
||||
|
||||
/**
|
||||
* Variables that need to be clean.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $clean_variables = array(
|
||||
"int" => array(
|
||||
"tid", "pid", "uid",
|
||||
"eid", "pmid", "fid",
|
||||
"aid", "rid", "sid",
|
||||
"vid", "cid", "bid",
|
||||
"hid", "gid", "mid",
|
||||
"wid", "lid", "iid",
|
||||
"did", "qid", "id"
|
||||
),
|
||||
"pos" => array(
|
||||
"page", "perpage"
|
||||
),
|
||||
"a-z" => array(
|
||||
"sortby", "order"
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Variables that are to be ignored from cleansing process
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $ignore_clean_variables = array();
|
||||
|
||||
/**
|
||||
* Using built in shutdown functionality provided by register_shutdown_function for < PHP 5?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $use_shutdown = true;
|
||||
|
||||
/**
|
||||
* Debug mode?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $debug_mode = false;
|
||||
|
||||
/**
|
||||
* Binary database fields need to be handled differently
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $binary_fields = array(
|
||||
'adminlog' => array('ipaddress' => true),
|
||||
'adminsessions' => array('ip' => true),
|
||||
'maillogs' => array('ipaddress' => true),
|
||||
'moderatorlog' => array('ipaddress' => true),
|
||||
'pollvotes' => array('ipaddress' => true),
|
||||
'posts' => array('ipaddress' => true),
|
||||
'privatemessages' => array('ipaddress' => true),
|
||||
'searchlog' => array('ipaddress' => true),
|
||||
'sessions' => array('ip' => true),
|
||||
'threadratings' => array('ipaddress' => true),
|
||||
'users' => array('regip' => true, 'lastip' => true),
|
||||
'spamlog' => array('ipaddress' => true),
|
||||
);
|
||||
|
||||
/**
|
||||
* The cache instance to use.
|
||||
*
|
||||
* @var datacache
|
||||
*/
|
||||
public $cache;
|
||||
|
||||
/**
|
||||
* The base URL to assets.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $asset_url = null;
|
||||
/**
|
||||
* String input constant for use with get_input().
|
||||
*
|
||||
* @see get_input
|
||||
*/
|
||||
const INPUT_STRING = 0;
|
||||
/**
|
||||
* Integer input constant for use with get_input().
|
||||
*
|
||||
* @see get_input
|
||||
*/
|
||||
const INPUT_INT = 1;
|
||||
/**
|
||||
* Array input constant for use with get_input().
|
||||
*
|
||||
* @see get_input
|
||||
*/
|
||||
const INPUT_ARRAY = 2;
|
||||
/**
|
||||
* Float input constant for use with get_input().
|
||||
*
|
||||
* @see get_input
|
||||
*/
|
||||
const INPUT_FLOAT = 3;
|
||||
/**
|
||||
* Boolean input constant for use with get_input().
|
||||
*
|
||||
* @see get_input
|
||||
*/
|
||||
const INPUT_BOOL = 4;
|
||||
|
||||
/**
|
||||
* Constructor of class.
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
// Set up MyBB
|
||||
$protected = array("_GET", "_POST", "_SERVER", "_COOKIE", "_FILES", "_ENV", "GLOBALS");
|
||||
foreach($protected as $var)
|
||||
{
|
||||
if(isset($_POST[$var]) || isset($_GET[$var]) || isset($_COOKIE[$var]) || isset($_FILES[$var]))
|
||||
{
|
||||
die("Hacking attempt");
|
||||
}
|
||||
}
|
||||
|
||||
if(defined("IGNORE_CLEAN_VARS"))
|
||||
{
|
||||
if(!is_array(IGNORE_CLEAN_VARS))
|
||||
{
|
||||
$this->ignore_clean_variables = array(IGNORE_CLEAN_VARS);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->ignore_clean_variables = IGNORE_CLEAN_VARS;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine Magic Quotes Status (< PHP 6.0)
|
||||
if(version_compare(PHP_VERSION, '6.0', '<'))
|
||||
{
|
||||
if(@get_magic_quotes_gpc())
|
||||
{
|
||||
$this->magicquotes = 1;
|
||||
$this->strip_slashes_array($_POST);
|
||||
$this->strip_slashes_array($_GET);
|
||||
$this->strip_slashes_array($_COOKIE);
|
||||
}
|
||||
@set_magic_quotes_runtime(0);
|
||||
@ini_set("magic_quotes_gpc", 0);
|
||||
@ini_set("magic_quotes_runtime", 0);
|
||||
}
|
||||
|
||||
// Determine input
|
||||
$this->parse_incoming($_GET);
|
||||
$this->parse_incoming($_POST);
|
||||
|
||||
if($_SERVER['REQUEST_METHOD'] == "POST")
|
||||
{
|
||||
$this->request_method = "post";
|
||||
}
|
||||
else if($_SERVER['REQUEST_METHOD'] == "GET")
|
||||
{
|
||||
$this->request_method = "get";
|
||||
}
|
||||
|
||||
// If we've got register globals on, then kill them too
|
||||
if(@ini_get("register_globals") == 1)
|
||||
{
|
||||
$this->unset_globals($_POST);
|
||||
$this->unset_globals($_GET);
|
||||
$this->unset_globals($_FILES);
|
||||
$this->unset_globals($_COOKIE);
|
||||
}
|
||||
$this->clean_input();
|
||||
|
||||
$safe_mode_status = @ini_get("safe_mode");
|
||||
if($safe_mode_status == 1 || strtolower($safe_mode_status) == 'on')
|
||||
{
|
||||
$this->safemode = true;
|
||||
}
|
||||
|
||||
// Are we running on a development server?
|
||||
if(isset($_SERVER['MYBB_DEV_MODE']) && $_SERVER['MYBB_DEV_MODE'] == 1)
|
||||
{
|
||||
$this->dev_mode = 1;
|
||||
}
|
||||
|
||||
// Are we running in debug mode?
|
||||
if(isset($this->input['debug']) && $this->input['debug'] == 1)
|
||||
{
|
||||
$this->debug_mode = true;
|
||||
}
|
||||
|
||||
if(isset($this->input['action']) && $this->input['action'] == "mybb_logo")
|
||||
{
|
||||
require_once dirname(__FILE__)."/mybb_group.php";
|
||||
output_logo();
|
||||
}
|
||||
|
||||
if(isset($this->input['intcheck']) && $this->input['intcheck'] == 1)
|
||||
{
|
||||
die("MYBB");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the incoming variables.
|
||||
*
|
||||
* @param array $array The array of incoming variables.
|
||||
*/
|
||||
function parse_incoming($array)
|
||||
{
|
||||
if(!is_array($array))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($array as $key => $val)
|
||||
{
|
||||
$this->input[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the incoming cookies
|
||||
*
|
||||
*/
|
||||
function parse_cookies()
|
||||
{
|
||||
if(!is_array($_COOKIE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$prefix_length = strlen($this->settings['cookieprefix']);
|
||||
|
||||
foreach($_COOKIE as $key => $val)
|
||||
{
|
||||
if($prefix_length && substr($key, 0, $prefix_length) == $this->settings['cookieprefix'])
|
||||
{
|
||||
$key = substr($key, $prefix_length);
|
||||
|
||||
// Fixes conflicts with one board having a prefix and another that doesn't on the same domain
|
||||
// Gives priority to our cookies over others (overwrites them)
|
||||
if($this->cookies[$key])
|
||||
{
|
||||
unset($this->cookies[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($this->cookies[$key]))
|
||||
{
|
||||
$this->cookies[$key] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips slashes out of a given array.
|
||||
*
|
||||
* @param array $array The array to strip.
|
||||
*/
|
||||
function strip_slashes_array(&$array)
|
||||
{
|
||||
foreach($array as $key => $val)
|
||||
{
|
||||
if(is_array($array[$key]))
|
||||
{
|
||||
$this->strip_slashes_array($array[$key]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$array[$key] = stripslashes($array[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets globals from a specific array.
|
||||
*
|
||||
* @param array $array The array to unset from.
|
||||
*/
|
||||
function unset_globals($array)
|
||||
{
|
||||
if(!is_array($array))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach(array_keys($array) as $key)
|
||||
{
|
||||
unset($GLOBALS[$key]);
|
||||
unset($GLOBALS[$key]); // Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans predefined input variables.
|
||||
*
|
||||
*/
|
||||
function clean_input()
|
||||
{
|
||||
foreach($this->clean_variables as $type => $variables)
|
||||
{
|
||||
foreach($variables as $var)
|
||||
{
|
||||
// If this variable is in the ignored array, skip and move to next.
|
||||
if(in_array($var, $this->ignore_clean_variables))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isset($this->input[$var]))
|
||||
{
|
||||
switch($type)
|
||||
{
|
||||
case "int":
|
||||
$this->input[$var] = $this->get_input($var, MyBB::INPUT_INT);
|
||||
break;
|
||||
case "a-z":
|
||||
$this->input[$var] = preg_replace("#[^a-z\.\-_]#i", "", $this->get_input($var));
|
||||
break;
|
||||
case "pos":
|
||||
if(($this->input[$var] < 0 && $var != "page") || ($var == "page" && $this->input[$var] != "last" && $this->input[$var] < 0))
|
||||
$this->input[$var] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the input data type before usage.
|
||||
*
|
||||
* @param string $name Variable name ($mybb->input)
|
||||
* @param int $type The type of the variable to get. Should be one of MyBB::INPUT_INT, MyBB::INPUT_ARRAY or MyBB::INPUT_STRING.
|
||||
*
|
||||
* @return int|float|array|string Checked data. Type depending on $type
|
||||
*/
|
||||
function get_input($name, $type = MyBB::INPUT_STRING)
|
||||
{
|
||||
|
||||
switch($type)
|
||||
{
|
||||
case MyBB::INPUT_ARRAY:
|
||||
if(!isset($this->input[$name]) || !is_array($this->input[$name]))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
return $this->input[$name];
|
||||
case MyBB::INPUT_INT:
|
||||
if(!isset($this->input[$name]) || !is_numeric($this->input[$name]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (int)$this->input[$name];
|
||||
case MyBB::INPUT_FLOAT:
|
||||
if(!isset($this->input[$name]) || !is_numeric($this->input[$name]))
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
return (float)$this->input[$name];
|
||||
case MyBB::INPUT_BOOL:
|
||||
if(!isset($this->input[$name]) || !is_scalar($this->input[$name]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (bool)$this->input[$name];
|
||||
default:
|
||||
if(!isset($this->input[$name]) || !is_scalar($this->input[$name]))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
return $this->input[$name];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to an asset using the CDN URL if configured.
|
||||
*
|
||||
* @param string $path The path to the file.
|
||||
* @param bool $use_cdn Whether to use the configured CDN options.
|
||||
*
|
||||
* @return string The complete URL to the asset.
|
||||
*/
|
||||
public function get_asset_url($path = '', $use_cdn = true)
|
||||
{
|
||||
$path = (string) $path;
|
||||
$path = ltrim($path, '/');
|
||||
|
||||
if(substr($path, 0, 4) != 'http')
|
||||
{
|
||||
if(substr($path, 0, 2) == './')
|
||||
{
|
||||
$path = substr($path, 2);
|
||||
}
|
||||
|
||||
if($use_cdn && $this->settings['usecdn'] && !empty($this->settings['cdnurl']))
|
||||
{
|
||||
$base_path = rtrim($this->settings['cdnurl'], '/');
|
||||
}
|
||||
else
|
||||
{
|
||||
$base_path = rtrim($this->settings['bburl'], '/');
|
||||
}
|
||||
|
||||
$url = $base_path;
|
||||
|
||||
if(!empty($path))
|
||||
{
|
||||
$url = $base_path . '/' . $path;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = $path;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a generic error.
|
||||
*
|
||||
* @param string $code The error code.
|
||||
*/
|
||||
function trigger_generic_error($code)
|
||||
{
|
||||
global $error_handler;
|
||||
|
||||
switch($code)
|
||||
{
|
||||
case "cache_no_write":
|
||||
$message = "The data cache directory (cache/) needs to exist and be writable by the web server. Change its permissions so that it is writable (777 on Unix based servers).";
|
||||
$error_code = MYBB_CACHE_NO_WRITE;
|
||||
break;
|
||||
case "install_directory":
|
||||
$message = "The install directory (install/) still exists on your server and is not locked. To access MyBB please either remove this directory or create an empty file in it called 'lock'.";
|
||||
$error_code = MYBB_INSTALL_DIR_EXISTS;
|
||||
break;
|
||||
case "board_not_installed":
|
||||
$message = "Your board has not yet been installed and configured. Please do so before attempting to browse it.";
|
||||
$error_code = MYBB_NOT_INSTALLED;
|
||||
break;
|
||||
case "board_not_upgraded":
|
||||
$message = "Your board has not yet been upgraded. Please do so before attempting to browse it.";
|
||||
$error_code = MYBB_NOT_UPGRADED;
|
||||
break;
|
||||
case "sql_load_error":
|
||||
$message = "MyBB was unable to load the SQL extension. Please contact the MyBB Group for support. <a href=\"https://mybb.com\">MyBB Website</a>";
|
||||
$error_code = MYBB_SQL_LOAD_ERROR;
|
||||
break;
|
||||
case "apc_load_error":
|
||||
$message = "APC needs to be configured with PHP to use the APC cache support.";
|
||||
$error_code = MYBB_CACHEHANDLER_LOAD_ERROR;
|
||||
break;
|
||||
case "eaccelerator_load_error":
|
||||
$message = "eAccelerator needs to be configured with PHP to use the eAccelerator cache support.";
|
||||
$error_code = MYBB_CACHEHANDLER_LOAD_ERROR;
|
||||
break;
|
||||
case "memcache_load_error":
|
||||
$message = "Your server does not have memcache support enabled.";
|
||||
$error_code = MYBB_CACHEHANDLER_LOAD_ERROR;
|
||||
break;
|
||||
case "memcached_load_error":
|
||||
$message = "Your server does not have memcached support enabled.";
|
||||
$error_code = MYBB_CACHEHANDLER_LOAD_ERROR;
|
||||
break;
|
||||
case "xcache_load_error":
|
||||
$message = "Xcache needs to be configured with PHP to use the Xcache cache support.";
|
||||
$error_code = MYBB_CACHEHANDLER_LOAD_ERROR;
|
||||
break;
|
||||
default:
|
||||
$message = "MyBB has experienced an internal error. Please contact the MyBB Group for support. <a href=\"https://mybb.com\">MyBB Website</a>";
|
||||
$error_code = MYBB_GENERAL;
|
||||
}
|
||||
$error_handler->trigger($message, $error_code);
|
||||
}
|
||||
|
||||
function __destruct()
|
||||
{
|
||||
// Run shutdown function
|
||||
if(function_exists("run_shutdown"))
|
||||
{
|
||||
run_shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do this here because the core is used on every MyBB page
|
||||
*/
|
||||
|
||||
$grouppermignore = array("gid", "type", "title", "description", "namestyle", "usertitle", "stars", "starimage", "image");
|
||||
$groupzerogreater = array("pmquota", "maxpmrecipients", "maxreputationsday", "attachquota", "maxemails", "maxposts", "edittimelimit", "maxreputationsperuser", "maxreputationsperthread", "emailfloodtime");
|
||||
$displaygroupfields = array("title", "description", "namestyle", "usertitle", "stars", "starimage", "image");
|
||||
|
||||
// These are fields in the usergroups table that are also forum permission specific.
|
||||
$fpermfields = array(
|
||||
'canview',
|
||||
'canviewthreads',
|
||||
'candlattachments',
|
||||
'canpostthreads',
|
||||
'canpostreplys',
|
||||
'canpostattachments',
|
||||
'canratethreads',
|
||||
'caneditposts',
|
||||
'candeleteposts',
|
||||
'candeletethreads',
|
||||
'caneditattachments',
|
||||
'canviewdeletionnotice',
|
||||
'modposts',
|
||||
'modthreads',
|
||||
'modattachments',
|
||||
'mod_edit_posts',
|
||||
'canpostpolls',
|
||||
'canvotepolls',
|
||||
'cansearch'
|
||||
);
|
||||
496
webroot/forum/inc/class_custommoderation.php
Normal file
496
webroot/forum/inc/class_custommoderation.php
Normal file
@@ -0,0 +1,496 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to execute a custom moderation tool
|
||||
*
|
||||
*/
|
||||
|
||||
class CustomModeration extends Moderation
|
||||
{
|
||||
/**
|
||||
* Get info on a tool
|
||||
*
|
||||
* @param int $tool_id Tool ID
|
||||
* @return array|bool Returns tool data (tid, type, name, description) in an array, otherwise boolean false.
|
||||
*/
|
||||
function tool_info($tool_id)
|
||||
{
|
||||
global $db;
|
||||
|
||||
// Get tool info
|
||||
$query = $db->simple_select("modtools", "*", 'tid='.(int)$tool_id);
|
||||
$tool = $db->fetch_array($query);
|
||||
if(!$tool['tid'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $tool;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute Custom Moderation Tool
|
||||
*
|
||||
* @param int $tool_id Tool ID
|
||||
* @param int|array Thread ID(s)
|
||||
* @param int|array Post ID(s)
|
||||
* @return string 'forum' or 'default' indicating where to redirect
|
||||
*/
|
||||
function execute($tool_id, $tids=0, $pids=0)
|
||||
{
|
||||
global $db;
|
||||
|
||||
// Get tool info
|
||||
$query = $db->simple_select("modtools", '*', 'tid='.(int)$tool_id);
|
||||
$tool = $db->fetch_array($query);
|
||||
if(!$tool['tid'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Format single tid and pid
|
||||
if(!is_array($tids))
|
||||
{
|
||||
$tids = array($tids);
|
||||
}
|
||||
if(!is_array($pids))
|
||||
{
|
||||
$pids = array($pids);
|
||||
}
|
||||
|
||||
// Unserialize custom moderation
|
||||
$post_options = my_unserialize($tool['postoptions']);
|
||||
$thread_options = my_unserialize($tool['threadoptions']);
|
||||
|
||||
// If the tool type is a post tool, then execute the post moderation
|
||||
$deleted_thread = 0;
|
||||
if($tool['type'] == 'p')
|
||||
{
|
||||
$deleted_thread = $this->execute_post_moderation($post_options, $pids, $tids);
|
||||
}
|
||||
// Always execute thead moderation
|
||||
$this->execute_thread_moderation($thread_options, $tids);
|
||||
|
||||
// If the thread is deleted, indicate to the calling script to redirect to the forum, and not the nonexistant thread
|
||||
if($thread_options['deletethread'] == 1 || $deleted_thread === 1)
|
||||
{
|
||||
return 'forum';
|
||||
}
|
||||
return 'default';
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute Inline Post Moderation
|
||||
*
|
||||
* @param array $post_options Moderation information
|
||||
* @param array $pids Post IDs
|
||||
* @param array|int $tid Thread IDs (in order of dateline ascending). Only the first one will be used
|
||||
* @return boolean true
|
||||
*/
|
||||
function execute_post_moderation($post_options=array(), $pids=array(), $tid)
|
||||
{
|
||||
global $db, $mybb, $lang;
|
||||
|
||||
if(is_array($tid))
|
||||
{
|
||||
$tid = (int)$tid[0]; // There's only 1 thread when doing inline post moderation
|
||||
// The thread chosen is the first thread in the array of tids.
|
||||
// It is recommended that this be the tid of the oldest post
|
||||
}
|
||||
|
||||
// Get the information about thread
|
||||
$thread = get_thread($tid);
|
||||
|
||||
// If deleting posts, only do that
|
||||
if($post_options['deleteposts'] == 1)
|
||||
{
|
||||
foreach($pids as $pid)
|
||||
{
|
||||
$this->delete_post($pid);
|
||||
}
|
||||
|
||||
$delete_tids = array();
|
||||
$imploded_pids = implode(",", array_map("intval", $pids));
|
||||
$query = $db->simple_select("threads", "tid", "firstpost IN ({$imploded_pids})");
|
||||
while($threadid = $db->fetch_field($query, "tid"))
|
||||
{
|
||||
$delete_tids[] = $threadid;
|
||||
}
|
||||
if(!empty($delete_tids))
|
||||
{
|
||||
foreach($delete_tids as $delete_tid)
|
||||
{
|
||||
$this->delete_thread($delete_tid);
|
||||
}
|
||||
// return true here so the code in execute() above knows to redirect to the forum
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($post_options['mergeposts'] == 1) // Merge posts
|
||||
{
|
||||
$this->merge_posts($pids);
|
||||
}
|
||||
|
||||
if($post_options['approveposts'] == 'approve') // Approve posts
|
||||
{
|
||||
$this->approve_posts($pids);
|
||||
}
|
||||
elseif($post_options['approveposts'] == 'unapprove') // Unapprove posts
|
||||
{
|
||||
$this->unapprove_posts($pids);
|
||||
}
|
||||
elseif($post_options['approveposts'] == 'toggle') // Toggle post visibility
|
||||
{
|
||||
$this->toggle_post_visibility($pids);
|
||||
}
|
||||
|
||||
if($post_options['softdeleteposts'] == 'softdelete') // Soft delete posts
|
||||
{
|
||||
$this->soft_delete_posts($pids);
|
||||
}
|
||||
elseif($post_options['softdeleteposts'] == 'restore') // Restore posts
|
||||
{
|
||||
$this->restore_posts($pids);
|
||||
}
|
||||
elseif($post_options['softdeleteposts'] == 'toggle') // Toggle post visibility
|
||||
{
|
||||
$this->toggle_post_softdelete($pids);
|
||||
}
|
||||
|
||||
if($post_options['splitposts'] > 0 || $post_options['splitposts'] == -2) // Split posts
|
||||
{
|
||||
$query = $db->simple_select("posts", "COUNT(*) AS totalposts", "tid='{$tid}'");
|
||||
$count = $db->fetch_array($query);
|
||||
|
||||
if($count['totalposts'] == 1)
|
||||
{
|
||||
error($lang->error_cantsplitonepost);
|
||||
}
|
||||
|
||||
if($count['totalposts'] == count($pids))
|
||||
{
|
||||
error($lang->error_cantsplitall);
|
||||
}
|
||||
|
||||
if($post_options['splitposts'] == -2)
|
||||
{
|
||||
$post_options['splitposts'] = $thread['fid'];
|
||||
}
|
||||
if(empty($post_options['splitpostsnewsubject']))
|
||||
{
|
||||
// Enter in a subject if a predefined one does not exist.
|
||||
$post_options['splitpostsnewsubject'] = "{$lang->split_thread_subject} {$thread['subject']}";
|
||||
}
|
||||
$new_subject = str_ireplace('{subject}', $thread['subject'], $post_options['splitpostsnewsubject']);
|
||||
$new_tid = $this->split_posts($pids, $tid, $post_options['splitposts'], $new_subject);
|
||||
if($post_options['splitpostsclose'] == 'close') // Close new thread
|
||||
{
|
||||
$this->close_threads($new_tid);
|
||||
}
|
||||
if($post_options['splitpostsstick'] == 'stick') // Stick new thread
|
||||
{
|
||||
$this->stick_threads($new_tid);
|
||||
}
|
||||
if($post_options['splitpostsunapprove'] == 'unapprove') // Unapprove new thread
|
||||
{
|
||||
$this->unapprove_threads($new_tid, $thread['fid']);
|
||||
}
|
||||
if($post_options['splitthreadprefix'] != '0')
|
||||
{
|
||||
$this->apply_thread_prefix($new_tid, $post_options['splitthreadprefix']); // Add thread prefix to new thread
|
||||
}
|
||||
if(!empty($post_options['splitpostsaddreply'])) // Add reply to new thread
|
||||
{
|
||||
require_once MYBB_ROOT."inc/datahandlers/post.php";
|
||||
$posthandler = new PostDataHandler("insert");
|
||||
|
||||
if(empty($post_options['splitpostsreplysubject']))
|
||||
{
|
||||
$post_options['splitpostsreplysubject'] = 'RE: '.$new_subject;
|
||||
}
|
||||
else
|
||||
{
|
||||
$post_options['splitpostsreplysubject'] = str_ireplace('{username}', $mybb->user['username'], $post_options['splitpostsreplysubject']);
|
||||
$post_options['splitpostsreplysubject'] = str_ireplace('{subject}', $new_subject, $post_options['splitpostsreplysubject']);
|
||||
}
|
||||
|
||||
// Set the post data that came from the input to the $post array.
|
||||
$post = array(
|
||||
"tid" => $new_tid,
|
||||
"fid" => $post_options['splitposts'],
|
||||
"subject" => $post_options['splitpostsreplysubject'],
|
||||
"uid" => $mybb->user['uid'],
|
||||
"username" => $mybb->user['username'],
|
||||
"message" => $post_options['splitpostsaddreply'],
|
||||
"ipaddress" => my_inet_pton(get_ip()),
|
||||
);
|
||||
// Set up the post options from the input.
|
||||
$post['options'] = array(
|
||||
"signature" => 1,
|
||||
"emailnotify" => 0,
|
||||
"disablesmilies" => 0
|
||||
);
|
||||
|
||||
$posthandler->set_data($post);
|
||||
|
||||
if($posthandler->validate_post($post))
|
||||
{
|
||||
$posthandler->insert_post($post);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute Normal and Inline Thread Moderation
|
||||
*
|
||||
* @param array $thread_options Moderation information
|
||||
* @param array Thread IDs. Only the first one will be used, but it needs to be an array
|
||||
* @return boolean true
|
||||
*/
|
||||
function execute_thread_moderation($thread_options=array(), $tids=array())
|
||||
{
|
||||
global $db, $mybb;
|
||||
|
||||
$tid = (int)$tids[0]; // Take the first thread to get thread data from
|
||||
$query = $db->simple_select("threads", 'fid', "tid='$tid'");
|
||||
$thread = $db->fetch_array($query);
|
||||
|
||||
// If deleting threads, only do that
|
||||
if($thread_options['deletethread'] == 1)
|
||||
{
|
||||
foreach($tids as $tid)
|
||||
{
|
||||
$this->delete_thread($tid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($thread_options['mergethreads'] == 1 && count($tids) > 1) // Merge Threads (ugly temp code until find better fix)
|
||||
{
|
||||
$tid_list = implode(',', $tids);
|
||||
$options = array('order_by' => 'dateline', 'order_dir' => 'DESC');
|
||||
$query = $db->simple_select("threads", 'tid, subject', "tid IN ($tid_list)", $options); // Select threads from newest to oldest
|
||||
$last_tid = 0;
|
||||
while($tid = $db->fetch_array($query))
|
||||
{
|
||||
if($last_tid != 0)
|
||||
{
|
||||
$this->merge_threads($last_tid, $tid['tid'], $tid['subject']); // And keep merging them until we get down to one thread.
|
||||
}
|
||||
$last_tid = $tid['tid'];
|
||||
}
|
||||
}
|
||||
if($thread_options['deletepoll'] == 1) // Delete poll
|
||||
{
|
||||
foreach($tids as $tid)
|
||||
{
|
||||
$this->delete_poll($tid);
|
||||
}
|
||||
}
|
||||
if($thread_options['removeredirects'] == 1) // Remove redirects
|
||||
{
|
||||
foreach($tids as $tid)
|
||||
{
|
||||
$this->remove_redirects($tid);
|
||||
}
|
||||
}
|
||||
|
||||
if($thread_options['removesubscriptions'] == 1) // Remove thread subscriptions
|
||||
{
|
||||
$this->remove_thread_subscriptions($tids, true);
|
||||
}
|
||||
|
||||
if($thread_options['approvethread'] == 'approve') // Approve thread
|
||||
{
|
||||
$this->approve_threads($tids, $thread['fid']);
|
||||
}
|
||||
elseif($thread_options['approvethread'] == 'unapprove') // Unapprove thread
|
||||
{
|
||||
$this->unapprove_threads($tids, $thread['fid']);
|
||||
}
|
||||
elseif($thread_options['approvethread'] == 'toggle') // Toggle thread visibility
|
||||
{
|
||||
$this->toggle_thread_visibility($tids, $thread['fid']);
|
||||
}
|
||||
|
||||
if($thread_options['softdeletethread'] == 'softdelete') // Soft delete thread
|
||||
{
|
||||
$this->soft_delete_threads($tids);
|
||||
}
|
||||
elseif($thread_options['softdeletethread'] == 'restore') // Restore thread
|
||||
{
|
||||
$this->restore_threads($tids);
|
||||
}
|
||||
elseif($thread_options['softdeletethread'] == 'toggle') // Toggle thread visibility
|
||||
{
|
||||
$this->toggle_thread_softdelete($tids);
|
||||
}
|
||||
|
||||
if($thread_options['openthread'] == 'open') // Open thread
|
||||
{
|
||||
$this->open_threads($tids);
|
||||
}
|
||||
elseif($thread_options['openthread'] == 'close') // Close thread
|
||||
{
|
||||
$this->close_threads($tids);
|
||||
}
|
||||
elseif($thread_options['openthread'] == 'toggle') // Toggle thread visibility
|
||||
{
|
||||
$this->toggle_thread_status($tids);
|
||||
}
|
||||
|
||||
if($thread_options['stickthread'] == 'stick') // Stick thread
|
||||
{
|
||||
$this->stick_threads($tids);
|
||||
}
|
||||
elseif($thread_options['stickthread'] == 'unstick') // Unstick thread
|
||||
{
|
||||
$this->unstick_threads($tids);
|
||||
}
|
||||
elseif($thread_options['stickthread'] == 'toggle') // Toggle thread importance
|
||||
{
|
||||
$this->toggle_thread_importance($tids);
|
||||
}
|
||||
|
||||
if($thread_options['threadprefix'] != '-1')
|
||||
{
|
||||
$this->apply_thread_prefix($tids, $thread_options['threadprefix']); // Update thread prefix
|
||||
}
|
||||
|
||||
if(my_strtolower(trim($thread_options['newsubject'])) != '{subject}') // Update thread subjects
|
||||
{
|
||||
$this->change_thread_subject($tids, $thread_options['newsubject']);
|
||||
}
|
||||
if(!empty($thread_options['addreply'])) // Add reply to thread
|
||||
{
|
||||
$tid_list = implode(',', $tids);
|
||||
$query = $db->simple_select("threads", 'uid, fid, subject, tid, firstpost, closed', "tid IN ($tid_list) AND closed NOT LIKE 'moved|%'");
|
||||
require_once MYBB_ROOT."inc/datahandlers/post.php";
|
||||
|
||||
// Loop threads adding a reply to each one
|
||||
while($thread = $db->fetch_array($query))
|
||||
{
|
||||
$posthandler = new PostDataHandler("insert");
|
||||
|
||||
if(empty($thread_options['replysubject']))
|
||||
{
|
||||
$new_subject = 'RE: '.$thread['subject'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$new_subject = str_ireplace('{username}', $mybb->user['username'], $thread_options['replysubject']);
|
||||
$new_subject = str_ireplace('{subject}', $thread['subject'], $new_subject);
|
||||
}
|
||||
|
||||
// Set the post data that came from the input to the $post array.
|
||||
$post = array(
|
||||
"tid" => $thread['tid'],
|
||||
"replyto" => $thread['firstpost'],
|
||||
"fid" => $thread['fid'],
|
||||
"subject" => $new_subject,
|
||||
"uid" => $mybb->user['uid'],
|
||||
"username" => $mybb->user['username'],
|
||||
"message" => $thread_options['addreply'],
|
||||
"ipaddress" => my_inet_pton(get_ip()),
|
||||
);
|
||||
|
||||
// Set up the post options from the input.
|
||||
$post['options'] = array(
|
||||
"signature" => 1,
|
||||
"emailnotify" => 0,
|
||||
"disablesmilies" => 0
|
||||
);
|
||||
|
||||
if($thread['closed'] == 1)
|
||||
{
|
||||
// Keep this thread closed
|
||||
$post['modoptions']['closethread'] = 1;
|
||||
}
|
||||
|
||||
$posthandler->set_data($post);
|
||||
if($posthandler->validate_post($post))
|
||||
{
|
||||
$posthandler->insert_post($post);
|
||||
}
|
||||
}
|
||||
}
|
||||
if($thread_options['movethread'] > 0 && $thread_options['movethread'] != $thread['fid']) // Move thread
|
||||
{
|
||||
if($thread_options['movethreadredirect'] == 1) // Move Thread with redirect
|
||||
{
|
||||
$time = TIME_NOW + ($thread_options['movethreadredirectexpire'] * 86400);
|
||||
foreach($tids as $tid)
|
||||
{
|
||||
$this->move_thread($tid, $thread_options['movethread'], 'redirect', $time);
|
||||
}
|
||||
}
|
||||
else // Normal move
|
||||
{
|
||||
$this->move_threads($tids, $thread_options['movethread']);
|
||||
}
|
||||
}
|
||||
if($thread_options['copythread'] > 0 || $thread_options['copythread'] == -2) // Copy thread
|
||||
{
|
||||
if($thread_options['copythread'] == -2)
|
||||
{
|
||||
$thread_options['copythread'] = $thread['fid'];
|
||||
}
|
||||
foreach($tids as $tid)
|
||||
{
|
||||
$new_tid = $this->move_thread($tid, $thread_options['copythread'], 'copy');
|
||||
}
|
||||
}
|
||||
if(!empty($thread_options['recountrebuild']))
|
||||
{
|
||||
require_once MYBB_ROOT.'/inc/functions_rebuild.php';
|
||||
|
||||
foreach($tids as $tid)
|
||||
{
|
||||
rebuild_thread_counters($tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have a PM subject and PM message?
|
||||
if(isset($thread_options['pm_subject']) && $thread_options['pm_subject'] != '' && isset($thread_options['pm_message']) && $thread_options['pm_message'] != '')
|
||||
{
|
||||
$tid_list = implode(',', $tids);
|
||||
|
||||
// For each thread, we send a PM to the author
|
||||
$query = $db->simple_select("threads", 'uid', "tid IN ($tid_list)");
|
||||
while($uid = $db->fetch_field($query, 'uid'))
|
||||
{
|
||||
// Let's send our PM
|
||||
$pm = array(
|
||||
'subject' => $thread_options['pm_subject'],
|
||||
'message' => $thread_options['pm_message'],
|
||||
'touid' => $uid
|
||||
);
|
||||
send_pm($pm, $mybb->user['uid'], 1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
1342
webroot/forum/inc/class_datacache.php
Normal file
1342
webroot/forum/inc/class_datacache.php
Normal file
File diff suppressed because it is too large
Load Diff
652
webroot/forum/inc/class_error.php
Normal file
652
webroot/forum/inc/class_error.php
Normal file
@@ -0,0 +1,652 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
// Set to 1 if receiving a blank page (template failure).
|
||||
define("MANUAL_WARNINGS", 0);
|
||||
|
||||
// Define Custom MyBB error handler constants with a value not used by php's error handler.
|
||||
define("MYBB_SQL", 20);
|
||||
define("MYBB_TEMPLATE", 30);
|
||||
define("MYBB_GENERAL", 40);
|
||||
define("MYBB_NOT_INSTALLED", 41);
|
||||
define("MYBB_NOT_UPGRADED", 42);
|
||||
define("MYBB_INSTALL_DIR_EXISTS", 43);
|
||||
define("MYBB_SQL_LOAD_ERROR", 44);
|
||||
define("MYBB_CACHE_NO_WRITE", 45);
|
||||
define("MYBB_CACHEHANDLER_LOAD_ERROR", 46);
|
||||
|
||||
if(!defined("E_RECOVERABLE_ERROR"))
|
||||
{
|
||||
// This constant has been defined since PHP 5.2.
|
||||
define("E_RECOVERABLE_ERROR", 4096);
|
||||
}
|
||||
|
||||
if(!defined("E_DEPRECATED"))
|
||||
{
|
||||
// This constant has been defined since PHP 5.3.
|
||||
define("E_DEPRECATED", 8192);
|
||||
}
|
||||
|
||||
if(!defined("E_USER_DEPRECATED"))
|
||||
{
|
||||
// This constant has been defined since PHP 5.3.
|
||||
define("E_USER_DEPRECATED", 16384);
|
||||
}
|
||||
|
||||
class errorHandler {
|
||||
|
||||
/**
|
||||
* Array of all of the error types
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $error_types = array(
|
||||
E_ERROR => 'Error',
|
||||
E_WARNING => 'Warning',
|
||||
E_PARSE => 'Parsing Error',
|
||||
E_NOTICE => 'Notice',
|
||||
E_CORE_ERROR => 'Core Error',
|
||||
E_CORE_WARNING => 'Core Warning',
|
||||
E_COMPILE_ERROR => 'Compile Error',
|
||||
E_COMPILE_WARNING => 'Compile Warning',
|
||||
E_DEPRECATED => 'Deprecated Warning',
|
||||
E_USER_ERROR => 'User Error',
|
||||
E_USER_WARNING => 'User Warning',
|
||||
E_USER_NOTICE => 'User Notice',
|
||||
E_USER_DEPRECATED => 'User Deprecated Warning',
|
||||
E_STRICT => 'Runtime Notice',
|
||||
E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
|
||||
MYBB_SQL => 'MyBB SQL Error',
|
||||
MYBB_TEMPLATE => 'MyBB Template Error',
|
||||
MYBB_GENERAL => 'MyBB Error',
|
||||
MYBB_NOT_INSTALLED => 'MyBB Error',
|
||||
MYBB_NOT_UPGRADED => 'MyBB Error',
|
||||
MYBB_INSTALL_DIR_EXISTS => 'MyBB Error',
|
||||
MYBB_SQL_LOAD_ERROR => 'MyBB Error',
|
||||
MYBB_CACHE_NO_WRITE => 'MyBB Error',
|
||||
MYBB_CACHEHANDLER_LOAD_ERROR => 'MyBB Error',
|
||||
);
|
||||
|
||||
/**
|
||||
* Array of MyBB error types
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $mybb_error_types = array(
|
||||
MYBB_SQL,
|
||||
MYBB_TEMPLATE,
|
||||
MYBB_GENERAL,
|
||||
MYBB_NOT_INSTALLED,
|
||||
MYBB_NOT_UPGRADED,
|
||||
MYBB_INSTALL_DIR_EXISTS,
|
||||
MYBB_SQL_LOAD_ERROR,
|
||||
MYBB_CACHE_NO_WRITE,
|
||||
MYBB_CACHEHANDLER_LOAD_ERROR,
|
||||
);
|
||||
|
||||
/**
|
||||
* Array of all of the error types to ignore
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $ignore_types = array(
|
||||
E_DEPRECATED,
|
||||
E_NOTICE,
|
||||
E_USER_NOTICE,
|
||||
E_STRICT
|
||||
);
|
||||
|
||||
/**
|
||||
* String of all the warnings collected
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $warnings = "";
|
||||
|
||||
/**
|
||||
* Is MyBB in an errornous state? (Have we received an error?)
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $has_errors = false;
|
||||
|
||||
/**
|
||||
* Initializes the error handler
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
// Lets set the error handler in here so we can just do $handler = new errorHandler() and be all set up.
|
||||
$error_types = E_ALL;
|
||||
foreach($this->ignore_types as $bit)
|
||||
{
|
||||
$error_types = $error_types & ~$bit;
|
||||
}
|
||||
error_reporting($error_types);
|
||||
set_error_handler(array(&$this, "error"), $error_types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a error for processing.
|
||||
*
|
||||
* @param string $type The error type (i.e. E_ERROR, E_FATAL)
|
||||
* @param string $message The error message
|
||||
* @param string $file The error file
|
||||
* @param integer $line The error line
|
||||
* @return boolean True if parsing was a success, otherwise assume a error
|
||||
*/
|
||||
function error($type, $message, $file=null, $line=0)
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
// Error reporting turned off (either globally or by @ before erroring statement)
|
||||
if(error_reporting() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(in_array($type, $this->ignore_types))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$file = str_replace(MYBB_ROOT, "", $file);
|
||||
|
||||
$this->has_errors = true;
|
||||
|
||||
// For some reason in the installer this setting is set to "<"
|
||||
$accepted_error_types = array('both', 'error', 'warning', 'none');
|
||||
if(!in_array($mybb->settings['errortypemedium'], $accepted_error_types))
|
||||
{
|
||||
$mybb->settings['errortypemedium'] = "both";
|
||||
}
|
||||
|
||||
if(defined("IN_TASK"))
|
||||
{
|
||||
global $task;
|
||||
|
||||
require_once MYBB_ROOT."inc/functions_task.php";
|
||||
|
||||
$filestr = '';
|
||||
if($file)
|
||||
{
|
||||
$filestr = " - Line: $line - File: $file";
|
||||
}
|
||||
|
||||
add_task_log($task, "{$this->error_types[$type]} - [$type] ".var_export($message, true)."{$filestr}");
|
||||
}
|
||||
|
||||
// Saving error to log file.
|
||||
if($mybb->settings['errorlogmedium'] == "log" || $mybb->settings['errorlogmedium'] == "both")
|
||||
{
|
||||
$this->log_error($type, $message, $file, $line);
|
||||
}
|
||||
|
||||
// Are we emailing the Admin a copy?
|
||||
if($mybb->settings['errorlogmedium'] == "mail" || $mybb->settings['errorlogmedium'] == "both")
|
||||
{
|
||||
$this->email_error($type, $message, $file, $line);
|
||||
}
|
||||
|
||||
// SQL Error
|
||||
if($type == MYBB_SQL)
|
||||
{
|
||||
$this->output_error($type, $message, $file, $line);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do we have a PHP error?
|
||||
if(my_strpos(my_strtolower($this->error_types[$type]), 'warning') === false)
|
||||
{
|
||||
$this->output_error($type, $message, $file, $line);
|
||||
}
|
||||
// PHP Error
|
||||
else
|
||||
{
|
||||
if($mybb->settings['errortypemedium'] == "none" || $mybb->settings['errortypemedium'] == "error")
|
||||
{
|
||||
echo "<div class=\"php_warning\">MyBB Internal: One or more warnings occurred. Please contact your administrator for assistance.</div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
global $templates;
|
||||
|
||||
$warning = "<strong>{$this->error_types[$type]}</strong> [$type] $message - Line: $line - File: $file PHP ".PHP_VERSION." (".PHP_OS.")<br />\n";
|
||||
if(is_object($templates) && method_exists($templates, "get") && !defined("IN_ADMINCP"))
|
||||
{
|
||||
$this->warnings .= $warning;
|
||||
$this->warnings .= $this->generate_backtrace();
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<div class=\"php_warning\">{$warning}".$this->generate_backtrace()."</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the warnings
|
||||
*
|
||||
* @return string|bool The warnings or false if no warnings exist
|
||||
*/
|
||||
function show_warnings()
|
||||
{
|
||||
global $lang, $templates;
|
||||
|
||||
if(empty($this->warnings))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Incase a template fails and we're receiving a blank page.
|
||||
if(MANUAL_WARNINGS)
|
||||
{
|
||||
echo $this->warnings."<br />";
|
||||
}
|
||||
|
||||
if(!$lang->warnings)
|
||||
{
|
||||
$lang->warnings = "The following warnings occurred:";
|
||||
}
|
||||
|
||||
$template_exists = false;
|
||||
|
||||
if(!is_object($templates) || !method_exists($templates, 'get'))
|
||||
{
|
||||
if(@file_exists(MYBB_ROOT."inc/class_templates.php"))
|
||||
{
|
||||
@require_once MYBB_ROOT."inc/class_templates.php";
|
||||
$templates = new templates;
|
||||
$template_exists = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$template_exists = true;
|
||||
}
|
||||
|
||||
$warning = '';
|
||||
if($template_exists == true)
|
||||
{
|
||||
eval("\$warning = \"".$templates->get("php_warnings")."\";");
|
||||
}
|
||||
|
||||
return $warning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a user created error
|
||||
* Example: $error_handler->trigger("Some Warning", E_USER_ERROR);
|
||||
*
|
||||
* @param string $message Message
|
||||
* @param string|int $type Type
|
||||
*/
|
||||
function trigger($message="", $type=E_USER_ERROR)
|
||||
{
|
||||
global $lang;
|
||||
|
||||
if(!$message)
|
||||
{
|
||||
$message = $lang->unknown_user_trigger;
|
||||
}
|
||||
|
||||
if(in_array($type, $this->mybb_error_types))
|
||||
{
|
||||
$this->error($type, $message);
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error($message, $type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the error in the specified error log file.
|
||||
*
|
||||
* @param string $type Warning type
|
||||
* @param string $message Warning message
|
||||
* @param string $file Warning file
|
||||
* @param integer $line Warning line
|
||||
*/
|
||||
function log_error($type, $message, $file, $line)
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
if($type == MYBB_SQL)
|
||||
{
|
||||
$message = "SQL Error: {$message['error_no']} - {$message['error']}\nQuery: {$message['query']}";
|
||||
}
|
||||
|
||||
// Do not log something that might be executable
|
||||
$message = str_replace('<?', '< ?', $message);
|
||||
|
||||
if(function_exists('debug_backtrace'))
|
||||
{
|
||||
ob_start();
|
||||
debug_print_backtrace();
|
||||
$trace = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
$back_trace = "\t<back_trace>{$trace}</back_trace>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$back_trace = '';
|
||||
}
|
||||
|
||||
$error_data = "<error>\n";
|
||||
$error_data .= "\t<dateline>".TIME_NOW."</dateline>\n";
|
||||
$error_data .= "\t<script>".$file."</script>\n";
|
||||
$error_data .= "\t<line>".$line."</line>\n";
|
||||
$error_data .= "\t<type>".$type."</type>\n";
|
||||
$error_data .= "\t<friendly_type>".$this->error_types[$type]."</friendly_type>\n";
|
||||
$error_data .= "\t<message>".$message."</message>\n";
|
||||
$error_data .= $back_trace;
|
||||
$error_data .= "</error>\n\n";
|
||||
|
||||
if(trim($mybb->settings['errorloglocation']) != "")
|
||||
{
|
||||
@error_log($error_data, 3, $mybb->settings['errorloglocation']);
|
||||
}
|
||||
else
|
||||
{
|
||||
@error_log($error_data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emails the error in the specified error log file.
|
||||
*
|
||||
* @param string $type Warning type
|
||||
* @param string $message Warning message
|
||||
* @param string $file Warning file
|
||||
* @param integer $line Warning line
|
||||
* @return bool returns false if no admin email is set
|
||||
*/
|
||||
function email_error($type, $message, $file, $line)
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
if(!$mybb->settings['adminemail'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if($type == MYBB_SQL)
|
||||
{
|
||||
$message = "SQL Error: {$message['error_no']} - {$message['error']}\nQuery: {$message['query']}";
|
||||
}
|
||||
|
||||
if(function_exists('debug_backtrace'))
|
||||
{
|
||||
ob_start();
|
||||
debug_print_backtrace();
|
||||
$trace = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
$back_trace = "\nBack Trace: {$trace}";
|
||||
}
|
||||
else
|
||||
{
|
||||
$back_trace = '';
|
||||
}
|
||||
|
||||
$message = "Your copy of MyBB running on {$mybb->settings['bbname']} ({$mybb->settings['bburl']}) has experienced an error. Details of the error include:\n---\nType: $type\nFile: $file (Line no. $line)\nMessage\n$message{$back_trace}";
|
||||
|
||||
@my_mail($mybb->settings['adminemail'], "MyBB error on {$mybb->settings['bbname']}", $message, $mybb->settings['adminemail']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param string $message
|
||||
* @param string $file
|
||||
* @param int $line
|
||||
*/
|
||||
function output_error($type, $message, $file, $line)
|
||||
{
|
||||
global $mybb, $parser, $lang;
|
||||
|
||||
if(!$mybb->settings['bbname'])
|
||||
{
|
||||
$mybb->settings['bbname'] = "MyBB";
|
||||
}
|
||||
|
||||
if($type == MYBB_SQL)
|
||||
{
|
||||
$title = "MyBB SQL Error";
|
||||
$error_message = "<p>MyBB has experienced an internal SQL error and cannot continue.</p>";
|
||||
if($mybb->settings['errortypemedium'] == "both" || $mybb->settings['errortypemedium'] == "error" || defined("IN_INSTALL") || defined("IN_UPGRADE"))
|
||||
{
|
||||
$message['query'] = htmlspecialchars_uni($message['query']);
|
||||
$message['error'] = htmlspecialchars_uni($message['error']);
|
||||
$error_message .= "<dl>\n";
|
||||
$error_message .= "<dt>SQL Error:</dt>\n<dd>{$message['error_no']} - {$message['error']}</dd>\n";
|
||||
if($message['query'] != "")
|
||||
{
|
||||
$error_message .= "<dt>Query:</dt>\n<dd>{$message['query']}</dd>\n";
|
||||
}
|
||||
$error_message .= "</dl>\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = "MyBB Internal Error";
|
||||
$error_message = "<p>MyBB has experienced an internal error and cannot continue.</p>";
|
||||
if($mybb->settings['errortypemedium'] == "both" || $mybb->settings['errortypemedium'] == "error" || defined("IN_INSTALL") || defined("IN_UPGRADE"))
|
||||
{
|
||||
$error_message .= "<dl>\n";
|
||||
$error_message .= "<dt>Error Type:</dt>\n<dd>{$this->error_types[$type]} ($type)</dd>\n";
|
||||
$error_message .= "<dt>Error Message:</dt>\n<dd>{$message}</dd>\n";
|
||||
if(!empty($file))
|
||||
{
|
||||
$error_message .= "<dt>Location:</dt><dd>File: {$file}<br />Line: {$line}</dd>\n";
|
||||
if(!@preg_match('#config\.php|settings\.php#', $file) && @file_exists($file))
|
||||
{
|
||||
$code_pre = @file($file);
|
||||
|
||||
$code = "";
|
||||
|
||||
if(isset($code_pre[$line-4]))
|
||||
{
|
||||
$code .= $line-3 . ". ".$code_pre[$line-4];
|
||||
}
|
||||
|
||||
if(isset($code_pre[$line-3]))
|
||||
{
|
||||
$code .= $line-2 . ". ".$code_pre[$line-3];
|
||||
}
|
||||
|
||||
if(isset($code_pre[$line-2]))
|
||||
{
|
||||
$code .= $line-1 . ". ".$code_pre[$line-2];
|
||||
}
|
||||
|
||||
$code .= $line . ". ".$code_pre[$line-1]; // The actual line.
|
||||
|
||||
if(isset($code_pre[$line]))
|
||||
{
|
||||
$code .= $line+1 . ". ".$code_pre[$line];
|
||||
}
|
||||
|
||||
if(isset($code_pre[$line+1]))
|
||||
{
|
||||
$code .= $line+2 . ". ".$code_pre[$line+1];
|
||||
}
|
||||
|
||||
if(isset($code_pre[$line+2]))
|
||||
{
|
||||
$code .= $line+3 . ". ".$code_pre[$line+2];
|
||||
}
|
||||
|
||||
unset($code_pre);
|
||||
|
||||
$parser_exists = false;
|
||||
|
||||
if(!is_object($parser) || !method_exists($parser, 'mycode_parse_php'))
|
||||
{
|
||||
if(@file_exists(MYBB_ROOT."inc/class_parser.php"))
|
||||
{
|
||||
@require_once MYBB_ROOT."inc/class_parser.php";
|
||||
$parser = new postParser;
|
||||
$parser_exists = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$parser_exists = true;
|
||||
}
|
||||
|
||||
if($parser_exists)
|
||||
{
|
||||
$code = $parser->mycode_parse_php($code, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$code = @nl2br($code);
|
||||
}
|
||||
|
||||
$error_message .= "<dt>Code:</dt><dd>{$code}</dd>\n";
|
||||
}
|
||||
}
|
||||
$backtrace = $this->generate_backtrace();
|
||||
if($backtrace && !in_array($type, $this->mybb_error_types))
|
||||
{
|
||||
$error_message .= "<dt>Backtrace:</dt><dd>{$backtrace}</dd>\n";
|
||||
}
|
||||
$error_message .= "</dl>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($lang->settings['charset']))
|
||||
{
|
||||
$charset = $lang->settings['charset'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$charset = 'UTF-8';
|
||||
}
|
||||
|
||||
if(!headers_sent() && !defined("IN_INSTALL") && !defined("IN_UPGRADE"))
|
||||
{
|
||||
@header('HTTP/1.1 503 Service Temporarily Unavailable');
|
||||
@header('Status: 503 Service Temporarily Unavailable');
|
||||
@header('Retry-After: 1800');
|
||||
@header("Content-type: text/html; charset={$charset}");
|
||||
$file_name = htmlspecialchars_uni(basename($_SERVER['SCRIPT_FILENAME']));
|
||||
|
||||
echo <<<EOF
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head profile="http://gmpg.org/xfn/11">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>{$mybb->settings['bbname']} - Internal Error</title>
|
||||
<style type="text/css">
|
||||
body { background: #efefef; color: #000; font-family: Tahoma,Verdana,Arial,Sans-Serif; font-size: 12px; text-align: center; line-height: 1.4; }
|
||||
a:link { color: #026CB1; text-decoration: none; }
|
||||
a:visited { color: #026CB1; text-decoration: none; }
|
||||
a:hover, a:active { color: #000; text-decoration: underline; }
|
||||
#container { width: 600px; padding: 20px; background: #fff; border: 1px solid #e4e4e4; margin: 100px auto; text-align: left; -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; }
|
||||
h1 { margin: 0; background: url({$file_name}?action=mybb_logo) no-repeat; height: 82px; width: 248px; }
|
||||
#content { border: 1px solid #026CB1; background: #fff; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; }
|
||||
h2 { font-size: 12px; padding: 4px; background: #026CB1; color: #fff; margin: 0; }
|
||||
.invisible { display: none; }
|
||||
#error { padding: 6px; }
|
||||
#footer { font-size: 12px; border-top: 1px dotted #DDDDDD; padding-top: 10px; }
|
||||
dt { font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="logo">
|
||||
<h1><a href="https://mybb.com/" title="MyBB"><span class="invisible">MyBB</span></a></h1>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<h2>{$title}</h2>
|
||||
|
||||
<div id="error">
|
||||
{$error_message}
|
||||
<p id="footer">Please contact the <a href="https://mybb.com">MyBB Group</a> for technical support.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
EOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo <<<EOF
|
||||
<style type="text/css">
|
||||
#mybb_error_content { border: 1px solid #026CB1; background: #fff; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; }
|
||||
#mybb_error_content a:link { color: #026CB1; text-decoration: none; }
|
||||
#mybb_error_content a:visited { color: #026CB1; text-decoration: none; }
|
||||
#mybb_error_content a:hover, a:active { color: #000; text-decoration: underline; }
|
||||
#mybb_error_content h2 { font-size: 12px; padding: 4px; background: #026CB1; color: #fff; margin: 0; border-bottom: none; }
|
||||
#mybb_error_error { padding: 6px; }
|
||||
#mybb_error_footer { font-size: 12px; border-top: 1px dotted #DDDDDD; padding-top: 10px; }
|
||||
#mybb_error_content dt { font-weight: bold; }
|
||||
</style>
|
||||
<div id="mybb_error_content">
|
||||
<h2>{$title}</h2>
|
||||
<div id="mybb_error_error">
|
||||
{$error_message}
|
||||
<p id="mybb_error_footer">Please contact the <a href="https://mybb.com">MyBB Group</a> for technical support.</p>
|
||||
</div>
|
||||
</div>
|
||||
EOF;
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a backtrace if the server supports it.
|
||||
*
|
||||
* @return string The generated backtrace
|
||||
*/
|
||||
function generate_backtrace()
|
||||
{
|
||||
$backtrace = '';
|
||||
if(function_exists("debug_backtrace"))
|
||||
{
|
||||
$trace = debug_backtrace();
|
||||
$backtrace = "<table style=\"width: 100%; margin: 10px 0; border: 1px solid #aaa; border-collapse: collapse; border-bottom: 0;\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n";
|
||||
$backtrace .= "<thead><tr>\n";
|
||||
$backtrace .= "<th style=\"border-bottom: 1px solid #aaa; background: #ccc; padding: 4px; text-align: left; font-size: 11px;\">File</th>\n";
|
||||
$backtrace .= "<th style=\"border-bottom: 1px solid #aaa; background: #ccc; padding: 4px; text-align: left; font-size: 11px;\">Line</th>\n";
|
||||
$backtrace .= "<th style=\"border-bottom: 1px solid #aaa; background: #ccc; padding: 4px; text-align: left; font-size: 11px;\">Function</th>\n";
|
||||
$backtrace .= "</tr></thead>\n<tbody>\n";
|
||||
|
||||
// Strip off this function from trace
|
||||
array_shift($trace);
|
||||
|
||||
foreach($trace as $call)
|
||||
{
|
||||
if(empty($call['file'])) $call['file'] = "[PHP]";
|
||||
if(empty($call['line'])) $call['line'] = " ";
|
||||
if(!empty($call['class'])) $call['function'] = $call['class'].$call['type'].$call['function'];
|
||||
$call['file'] = str_replace(MYBB_ROOT, "/", $call['file']);
|
||||
$backtrace .= "<tr>\n";
|
||||
$backtrace .= "<td style=\"font-size: 11px; padding: 4px; border-bottom: 1px solid #ccc;\">{$call['file']}</td>\n";
|
||||
$backtrace .= "<td style=\"font-size: 11px; padding: 4px; border-bottom: 1px solid #ccc;\">{$call['line']}</td>\n";
|
||||
$backtrace .= "<td style=\"font-size: 11px; padding: 4px; border-bottom: 1px solid #ccc;\">{$call['function']}</td>\n";
|
||||
$backtrace .= "</tr>\n";
|
||||
}
|
||||
$backtrace .= "</tbody></table>\n";
|
||||
}
|
||||
return $backtrace;
|
||||
}
|
||||
}
|
||||
270
webroot/forum/inc/class_feedgeneration.php
Normal file
270
webroot/forum/inc/class_feedgeneration.php
Normal file
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
class FeedGenerator
|
||||
{
|
||||
/**
|
||||
* The type of feed to generate.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $feed_format = 'rss2.0';
|
||||
|
||||
/**
|
||||
* The feed to output.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $feed = "";
|
||||
|
||||
/**
|
||||
* Array of all of the items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $items = array();
|
||||
|
||||
/**
|
||||
* Array of the channel information.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $channel = array();
|
||||
|
||||
/**
|
||||
* Set the type of feed to be used.
|
||||
*
|
||||
* @param string $feed_format The feed type.
|
||||
*/
|
||||
function set_feed_format($feed_format)
|
||||
{
|
||||
if($feed_format == 'json')
|
||||
{
|
||||
$this->feed_format = 'json';
|
||||
}
|
||||
elseif($feed_format == 'atom1.0')
|
||||
{
|
||||
$this->feed_format = 'atom1.0';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->feed_format = 'rss2.0';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the channel information for the RSS feed.
|
||||
*
|
||||
* @param array $channel The channel information
|
||||
*/
|
||||
function set_channel($channel)
|
||||
{
|
||||
$this->channel = $channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item to the RSS feed.
|
||||
*
|
||||
* @param array $item The item.
|
||||
*/
|
||||
function add_item($item)
|
||||
{
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the feed.
|
||||
*
|
||||
*/
|
||||
function generate_feed()
|
||||
{
|
||||
global $lang;
|
||||
|
||||
// First, add the feed metadata.
|
||||
switch($this->feed_format)
|
||||
{
|
||||
// Ouput JSON formatted feed.
|
||||
case "json":
|
||||
$this->feed .= "{\n\t\"version\": ".json_encode('https://jsonfeed.org/version/1').",\n";
|
||||
$this->feed .= "\t\"title\": \"".$this->channel['title']."\",\n";
|
||||
$this->feed .= "\t\"home_page_url\": ".json_encode($this->channel['link']).",\n";
|
||||
$this->feed .= "\t\"feed_url\": ".json_encode($this->channel['link']."syndication.php").",\n";
|
||||
$this->feed .= "\t\"description\": ".json_encode($this->channel['description']).",\n";
|
||||
$this->feed .= "\t\"items\": [\n";
|
||||
$serial = 0;
|
||||
break;
|
||||
// Ouput Atom 1.0 formatted feed.
|
||||
case "atom1.0":
|
||||
$this->channel['date'] = gmdate("Y-m-d\TH:i:s\Z", $this->channel['date']);
|
||||
$this->feed .= "<?xml version=\"1.0\" encoding=\"{$lang->settings['charset']}\"?>\n";
|
||||
$this->feed .= "<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
|
||||
$this->feed .= "\t<title type=\"html\"><![CDATA[".$this->sanitize_content($this->channel['title'])."]]></title>\n";
|
||||
$this->feed .= "\t<subtitle type=\"html\"><![CDATA[".$this->sanitize_content($this->channel['description'])."]]></subtitle>\n";
|
||||
$this->feed .= "\t<link rel=\"self\" href=\"{$this->channel['link']}syndication.php\"/>\n";
|
||||
$this->feed .= "\t<id>{$this->channel['link']}</id>\n";
|
||||
$this->feed .= "\t<link rel=\"alternate\" type=\"text/html\" href=\"{$this->channel['link']}\"/>\n";
|
||||
$this->feed .= "\t<updated>{$this->channel['date']}</updated>\n";
|
||||
$this->feed .= "\t<generator uri=\"https://mybb.com\">MyBB</generator>\n";
|
||||
break;
|
||||
// The default is the RSS 2.0 format.
|
||||
default:
|
||||
$this->channel['date'] = gmdate("D, d M Y H:i:s O", $this->channel['date']);
|
||||
$this->feed .= "<?xml version=\"1.0\" encoding=\"{$lang->settings['charset']}\"?>\n";
|
||||
$this->feed .= "<rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
|
||||
$this->feed .= "\t<channel>\n";
|
||||
$this->feed .= "\t\t<title><![CDATA[".$this->sanitize_content($this->channel['title'])."]]></title>\n";
|
||||
$this->feed .= "\t\t<link>".$this->channel['link']."</link>\n";
|
||||
$this->feed .= "\t\t<description><![CDATA[".$this->sanitize_content($this->channel['description'])."]]></description>\n";
|
||||
$this->feed .= "\t\t<pubDate>".$this->channel['date']."</pubDate>\n";
|
||||
$this->feed .= "\t\t<generator>MyBB</generator>\n";
|
||||
}
|
||||
|
||||
// Now loop through all of the items and add them to the feed.
|
||||
foreach($this->items as $item)
|
||||
{
|
||||
if(!$item['date'])
|
||||
{
|
||||
$item['date'] = TIME_NOW;
|
||||
}
|
||||
switch($this->feed_format)
|
||||
{
|
||||
// Output JSON formatted feed.
|
||||
case "json":
|
||||
++$serial;
|
||||
$end = $serial < count($this->items) ? "," : "";
|
||||
$item_id = explode('tid=', $item['link']);
|
||||
if(empty($item['updated']))
|
||||
{
|
||||
$item['updated'] = $item['date'];
|
||||
}
|
||||
$this->feed .= "\t\t{\n";
|
||||
$this->feed .= "\t\t\t\"id\": \"".end($item_id)."\",\n";
|
||||
$this->feed .= "\t\t\t\"url\": ".json_encode($item['link']).",\n";
|
||||
$this->feed .= "\t\t\t\"title\": ".json_encode($item['title']).",\n";
|
||||
if(!empty($item['author']))
|
||||
{
|
||||
$this->feed .= "\t\t\t\"author\": {\n\t\t\t\t\"name\": ".json_encode($item['author']['name']).",\n";
|
||||
$this->feed .= "\t\t\t\t\"url\": ".json_encode($this->channel['link']."member.php?action=profile&uid=".$item['author']['uid'])."\n";
|
||||
$this->feed .= "\t\t\t},\n";
|
||||
}
|
||||
$this->feed .= "\t\t\t\"content_html\": ".json_encode($item['description']).",\n";
|
||||
$this->feed .= "\t\t\t\"date_published\": \"".date('c', $item['date'])."\",\n";
|
||||
$this->feed .= "\t\t\t\"date_modified \": \"".date('c', $item['updated'])."\"\n";
|
||||
$this->feed .= "\t\t}".$end."\n";
|
||||
break;
|
||||
// Output Atom 1.0 formatted feed.
|
||||
case "atom1.0":
|
||||
$item['date'] = date("Y-m-d\TH:i:s\Z", $item['date']);
|
||||
$this->feed .= "\t<entry xmlns=\"http://www.w3.org/2005/Atom\">\n";
|
||||
if(!empty($item['author']))
|
||||
{
|
||||
$author = "<a href=\"".$this->channel['link']."member.php?action=profile&uid=".$item['author']['uid']."\">".$item['author']['name']."</a>";
|
||||
$this->feed .= "\t\t<author>\n";
|
||||
$this->feed .= "\t\t\t<name type=\"html\" xml:space=\"preserve\"><![CDATA[".$this->sanitize_content($author)."]]></name>\n";
|
||||
$this->feed .= "\t\t</author>\n";
|
||||
}
|
||||
$this->feed .= "\t\t<published>{$item['date']}</published>\n";
|
||||
if(empty($item['updated']))
|
||||
{
|
||||
$item['updated'] = $item['date'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$item['updated'] = date("Y-m-d\TH:i:s\Z", $item['updated']);
|
||||
}
|
||||
$this->feed .= "\t\t<updated>{$item['updated']}</updated>\n";
|
||||
$this->feed .= "\t\t<link rel=\"alternate\" type=\"text/html\" href=\"{$item['link']}\" />\n";
|
||||
$this->feed .= "\t\t<id>{$item['link']}</id>\n";
|
||||
$this->feed .= "\t\t<title xml:space=\"preserve\"><![CDATA[".$this->sanitize_content($item['title'])."]]></title>\n";
|
||||
$this->feed .= "\t\t<content type=\"html\" xml:space=\"preserve\" xml:base=\"{$item['link']}\"><![CDATA[".$this->sanitize_content($item['description'])."]]></content>\n";
|
||||
$this->feed .= "\t\t<draft xmlns=\"http://purl.org/atom-blog/ns#\">false</draft>\n";
|
||||
$this->feed .= "\t</entry>\n";
|
||||
break;
|
||||
|
||||
// The default is the RSS 2.0 format.
|
||||
default:
|
||||
$item['date'] = date("D, d M Y H:i:s O", $item['date']);
|
||||
$this->feed .= "\t\t<item>\n";
|
||||
$this->feed .= "\t\t\t<title><![CDATA[".$this->sanitize_content($item['title'])."]]></title>\n";
|
||||
$this->feed .= "\t\t\t<link>".$item['link']."</link>\n";
|
||||
$this->feed .= "\t\t\t<pubDate>".$item['date']."</pubDate>\n";
|
||||
if(!empty($item['author']))
|
||||
{
|
||||
$author = "<a href=\"".$this->channel['link']."member.php?action=profile&uid=".$item['author']['uid']."\">".$item['author']['name']."</a>";
|
||||
$this->feed .= "\t\t\t<dc:creator><![CDATA[".$this->sanitize_content($author)."]]></dc:creator>\n";
|
||||
}
|
||||
$this->feed .= "\t\t\t<guid isPermaLink=\"false\">".$item['link']."</guid>\n";
|
||||
$this->feed .= "\t\t\t<description><![CDATA[".$item['description']."]]></description>\n";
|
||||
$this->feed .= "\t\t\t<content:encoded><![CDATA[".$item['description']."]]></content:encoded>\n";
|
||||
$this->feed .= "\t\t</item>\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now, neatly end the feed.
|
||||
switch($this->feed_format)
|
||||
{
|
||||
case "json":
|
||||
$this->feed .= "\t]\n}";
|
||||
break;
|
||||
case "atom1.0":
|
||||
$this->feed .= "</feed>";
|
||||
break;
|
||||
default:
|
||||
$this->feed .= "\t</channel>\n";
|
||||
$this->feed .= "</rss>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize content suitable for RSS feeds.
|
||||
*
|
||||
* @param string $string The string we wish to sanitize.
|
||||
* @return string The cleaned string.
|
||||
*/
|
||||
function sanitize_content($content)
|
||||
{
|
||||
$content = preg_replace("#&[^\s]([^\#])(?![a-z1-4]{1,10});#i", "&$1", $content);
|
||||
$content = str_replace("]]>", "]]]]><![CDATA[>", $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the feed.
|
||||
*/
|
||||
function output_feed()
|
||||
{
|
||||
global $lang;
|
||||
// Send an appropriate header to the browser.
|
||||
switch($this->feed_format)
|
||||
{
|
||||
case "json":
|
||||
header("Content-Type: application/json; charset=\"{$lang->settings['charset']}\"");
|
||||
break;
|
||||
case "atom1.0":
|
||||
header("Content-Type: application/atom+xml; charset=\"{$lang->settings['charset']}\"");
|
||||
break;
|
||||
default:
|
||||
header("Content-Type: text/xml; charset=\"{$lang->settings['charset']}\"");
|
||||
}
|
||||
|
||||
// If the feed hasn't been generated, do so.
|
||||
if($this->feed)
|
||||
{
|
||||
echo $this->feed;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->generate_feed();
|
||||
echo $this->feed;
|
||||
}
|
||||
}
|
||||
}
|
||||
242
webroot/forum/inc/class_feedparser.php
Normal file
242
webroot/forum/inc/class_feedparser.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
class FeedParser
|
||||
{
|
||||
/**
|
||||
* Array of all of the items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $items = array();
|
||||
|
||||
/**
|
||||
* Array of the channel information.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $channel = array();
|
||||
|
||||
/**
|
||||
* Any error the feed parser may encounter
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $error;
|
||||
|
||||
/**
|
||||
* Parses a feed with the specified filename (or URL)
|
||||
*
|
||||
* @param string $feed The path or URL of the feed
|
||||
* @return boolean True if parsing was a success, false if failure
|
||||
*/
|
||||
function parse_feed($feed)
|
||||
{
|
||||
// Include the XML parser
|
||||
require_once MYBB_ROOT."inc/class_xml.php";
|
||||
|
||||
// Load the feed we want to parse
|
||||
$contents = fetch_remote_file($feed);
|
||||
|
||||
// This is to work around some dodgy bug we've detected with certain installations of PHP
|
||||
// where certain characters would magically appear between the fetch_remote_file call
|
||||
// and here which break the feed being imported.
|
||||
if(strpos($contents, "<") !== 0)
|
||||
{
|
||||
$contents = substr($contents, strpos($contents, "<"));
|
||||
}
|
||||
if(strrpos($contents, ">")+1 !== strlen($contents))
|
||||
{
|
||||
$contents = substr($contents, 0, strrpos($contents, ">")+1);
|
||||
}
|
||||
|
||||
// Could not load the feed, return an error
|
||||
if(!$contents)
|
||||
{
|
||||
$this->error = "invalid_file";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the feed and get the tree
|
||||
$parser = new XMLParser($contents);
|
||||
$tree = $parser->get_tree();
|
||||
|
||||
// If the feed is invalid, throw back an error
|
||||
if($tree == false)
|
||||
{
|
||||
$this->error = "invalid_feed_xml";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Change array key names to lower case
|
||||
$tree = $this->keys_to_lowercase($tree);
|
||||
|
||||
// This is an RSS feed, parse it
|
||||
if(array_key_exists("rss", $tree))
|
||||
{
|
||||
$this->parse_rss($tree['rss']);
|
||||
}
|
||||
|
||||
// We don't know how to parse this feed
|
||||
else
|
||||
{
|
||||
$this->error = "unknown_feed_type";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an XML structure in the format of an RSS feed
|
||||
*
|
||||
* @param array $feed_contents PHP XML parser structure
|
||||
* @return boolean true
|
||||
*/
|
||||
function parse_rss($feed_contents)
|
||||
{
|
||||
foreach(array('title', 'link', 'description', 'pubdate') as $value)
|
||||
{
|
||||
if(!isset($feed_contents['channel'][$value]['value']))
|
||||
{
|
||||
$feed_contents['channel'][$value]['value'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch channel information from the parsed feed
|
||||
$this->channel = array(
|
||||
"title" => $feed_contents['channel']['title']['value'],
|
||||
"link" => $feed_contents['channel']['link']['value'],
|
||||
"description" => $feed_contents['channel']['description']['value'],
|
||||
"date" => $feed_contents['channel']['pubdate']['value'],
|
||||
"date_timestamp" => $this->get_rss_timestamp($feed_contents['channel']['pubdate']['value'])
|
||||
);
|
||||
|
||||
// The XML parser does not create a multidimensional array of items if there is one item, so fake it
|
||||
if(!array_key_exists("0", $feed_contents['channel']['item']))
|
||||
{
|
||||
$feed_contents['channel']['item'] = array($feed_contents['channel']['item']);
|
||||
}
|
||||
|
||||
// Loop through each of the items in the feed
|
||||
foreach($feed_contents['channel']['item'] as $feed_item)
|
||||
{
|
||||
// Here is a nice long stretch of code for parsing items, we do it this way because most elements are optional in an
|
||||
// item and we only want to assign what we have.
|
||||
|
||||
$item = array();
|
||||
|
||||
|
||||
// Set the item title if we have it
|
||||
if(array_key_exists("title", $feed_item))
|
||||
{
|
||||
$item['title'] = $feed_item['title']['value'];
|
||||
}
|
||||
|
||||
if(array_key_exists("description", $feed_item))
|
||||
{
|
||||
$item['description'] = $feed_item['description']['value'];
|
||||
}
|
||||
|
||||
if(array_key_exists("link", $feed_item))
|
||||
{
|
||||
$item['link'] = $feed_item['link']['value'];
|
||||
}
|
||||
|
||||
// If we have a pub date, store it and attempt to generate a unix timestamp from it
|
||||
if(array_key_exists("pubdate", $feed_item))
|
||||
{
|
||||
$item['date'] = $feed_item['pubdate']['value'];
|
||||
$item['date_timestamp'] = $this->get_rss_timestamp($item['date']);
|
||||
}
|
||||
|
||||
// If we have a GUID
|
||||
if(array_key_exists("guid", $feed_item))
|
||||
{
|
||||
$item['guid'] = $feed_item['guid']['value'];
|
||||
}
|
||||
// Otherwise, attempt to generate one from the link and item title
|
||||
else
|
||||
{
|
||||
$item['guid'] = md5($item['link'].$item['title']);
|
||||
}
|
||||
|
||||
// If we have some content, set it
|
||||
if(array_key_exists("content:encoded", $feed_item))
|
||||
{
|
||||
$item['content'] = $feed_item['content:encoded']['value'];
|
||||
}
|
||||
else if(array_key_exists("content", $feed_item))
|
||||
{
|
||||
$item['content'] = $feed_item['content']['value'];
|
||||
}
|
||||
|
||||
// We have a DC based creator, set it
|
||||
if(array_key_exists("dc:creator", $feed_item))
|
||||
{
|
||||
$item['author'] = $feed_item['dc:creator']['value'];
|
||||
}
|
||||
// Otherwise, attempt to use the author if we have it
|
||||
else if(array_key_exists("author", $feed_item))
|
||||
{
|
||||
$item['author'] = $feed_item['author']['value'];
|
||||
}
|
||||
|
||||
// Assign the item to our list of items
|
||||
$this->items[] = $item;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert all array keys within an array to lowercase
|
||||
*
|
||||
* @param array $array The array to be converted
|
||||
* @return array The converted array
|
||||
*/
|
||||
function keys_to_lowercase($array)
|
||||
{
|
||||
$new_array = array();
|
||||
foreach($array as $key => $value)
|
||||
{
|
||||
$new_key = strtolower($key);
|
||||
if(is_array($value))
|
||||
{
|
||||
$new_array[$new_key] = $this->keys_to_lowercase($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
$new_array[$new_key] = $value;
|
||||
}
|
||||
}
|
||||
return $new_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an RSS date stamp in to a unix timestamp
|
||||
*
|
||||
* @param string $date The RSS date
|
||||
* @return integer The unix timestamp (if successful), 0 if unsuccessful
|
||||
*/
|
||||
function get_rss_timestamp($date)
|
||||
{
|
||||
$stamp = strtotime($date);
|
||||
if($stamp <= 0)
|
||||
{
|
||||
if(preg_match("#\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2}#", $date, $result))
|
||||
{
|
||||
$date = str_replace(array("T", "+"), array(" ", " +"), $date);
|
||||
$date[23] = "";
|
||||
}
|
||||
$stamp = strtotime($date);
|
||||
}
|
||||
return $stamp;
|
||||
}
|
||||
}
|
||||
337
webroot/forum/inc/class_graph.php
Normal file
337
webroot/forum/inc/class_graph.php
Normal file
@@ -0,0 +1,337 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
class Graph {
|
||||
|
||||
/**
|
||||
* The width of the image.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $img_width = 1000;
|
||||
|
||||
/**
|
||||
* The height of the image.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $img_height = 300;
|
||||
|
||||
/**
|
||||
* The image resource handle.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
private $im;
|
||||
|
||||
/**
|
||||
* The amount of x pixels to start inside the image for the graph
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $inside_x = 65;
|
||||
|
||||
/**
|
||||
* The amount of y pixels to start inside the image for the graph
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $inside_y = 30;
|
||||
|
||||
/**
|
||||
* The width of the inside graph
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $inside_width = 930;
|
||||
|
||||
/**
|
||||
* The height of the inside graph
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $inside_height = 220;
|
||||
|
||||
/**
|
||||
* The x, y points for the graph
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $points = array();
|
||||
|
||||
/**
|
||||
* The corresponding x labels for the graph
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $x_labels = array();
|
||||
|
||||
/**
|
||||
* The bottom label for the graph
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $bottom_label = "";
|
||||
|
||||
/**
|
||||
* Constructor of class. Initializes the barebore graph.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Setup initial graph layout
|
||||
|
||||
// Check for GD >= 2, create base image
|
||||
if(gd_version() >= 2)
|
||||
{
|
||||
$this->im = imagecreatetruecolor($this->img_width, $this->img_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->im = imagecreate($this->img_width, $this->img_height);
|
||||
}
|
||||
|
||||
// No GD support, die.
|
||||
if(!$this->im)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(function_exists("imageantialias"))
|
||||
{
|
||||
imageantialias($this->im, true);
|
||||
}
|
||||
|
||||
// Fill the background
|
||||
imagefill($this->im, 0, 0, $this->color(239, 239, 239));
|
||||
|
||||
// Create our internal working graph box
|
||||
$inside_end_x = $this->inside_x+$this->inside_width;
|
||||
$inside_end_y = $this->inside_y+$this->inside_height;
|
||||
$this->image_create_rectangle($this->inside_x, $this->inside_y, $inside_end_x, $inside_end_y, 4, $this->color(254, 254, 254));
|
||||
|
||||
// Draw our three lines inside our internal working graph area
|
||||
for($i = 1; $i < 4; ++$i)
|
||||
{
|
||||
$y_value = $this->inside_y+(($this->inside_height/4)*$i);
|
||||
imageline($this->im, $this->inside_x, $y_value, $inside_end_x, $y_value, $this->color(185, 185, 185));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select and allocate a color to the internal image resource
|
||||
*
|
||||
* @param integer $red The red value
|
||||
* @param integer $green The green value
|
||||
* @param integer $blue The blue value
|
||||
* @return integer A color identifier
|
||||
*/
|
||||
private function color($red, $green, $blue)
|
||||
{
|
||||
return imagecolorallocate($this->im, $red, $green, $blue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a filled rectangle with optional rounded corners
|
||||
*
|
||||
* @param integer $x1 The initial x value
|
||||
* @param integer $y1 The initial y value
|
||||
* @param integer $x2 The ending x value
|
||||
* @param integer $y2 The ending y value
|
||||
* @param integer $radius The optional radius
|
||||
* @param integer $color The optional rectangle color (defaults to black)
|
||||
*/
|
||||
private function image_create_rectangle($x1, $y1, $x2, $y2, $radius=1, $color=null)
|
||||
{
|
||||
if($color == null)
|
||||
{
|
||||
$color = $this->color(0, 0, 0);
|
||||
}
|
||||
|
||||
// Draw our rectangle
|
||||
imagefilledrectangle($this->im, $x1, $y1+$radius, $x2, $y2-$radius, $color);
|
||||
imagefilledrectangle($this->im, $x1+$radius, $y1, $x2-$radius, $y2, $color);
|
||||
|
||||
if($radius > 0)
|
||||
{
|
||||
$diameter = $radius*2;
|
||||
|
||||
// Now draw our four corners on the rectangle
|
||||
imagefilledellipse($this->im, $x1+$radius, $y1+$radius, $diameter, $diameter, $color);
|
||||
imagefilledellipse($this->im, $x1+$radius, $y2-$radius, $diameter, $diameter, $color);
|
||||
imagefilledellipse($this->im, $x2-$radius, $y2-$radius, $diameter, $diameter, $color);
|
||||
imagefilledellipse($this->im, $x2-$radius, $y1+$radius, $diameter, $diameter, $color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nicer thick line for angled lines
|
||||
*
|
||||
* @param integer $x1 The initial x value
|
||||
* @param integer $y1 The initial y value
|
||||
* @param integer $x2 The ending x value
|
||||
* @param integer $y2 The ending y value
|
||||
* @param integer $color The optional rectangle color (defaults to black)
|
||||
* @param integer $thick The optional thickness (defaults to 1)
|
||||
* @return int
|
||||
*/
|
||||
private function imagelinethick($x1, $y1, $x2, $y2, $color, $thick = 1)
|
||||
{
|
||||
if($thick == 1)
|
||||
{
|
||||
return imageline($this->im, $x1, $y1, $x2, $y2, $color);
|
||||
}
|
||||
|
||||
$t = $thick / 2 - 0.5;
|
||||
if($x1 == $x2 || $y1 == $y2)
|
||||
{
|
||||
return imagefilledrectangle($this->im, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
|
||||
}
|
||||
|
||||
$k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
|
||||
$a = $t / sqrt(1 + pow($k, 2));
|
||||
$points = array(
|
||||
round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
|
||||
round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
|
||||
round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
|
||||
round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a),
|
||||
);
|
||||
imagefilledpolygon($this->im, $points, 4, $color);
|
||||
|
||||
return imagepolygon($this->im, $points, 4, $color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an array of x, y points to the internal points array
|
||||
*
|
||||
* @param array $points The array of x, y points to add
|
||||
*/
|
||||
public function add_points($points)
|
||||
{
|
||||
$this->points = array_merge($this->points, $points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an array of x labels to the internal labels array
|
||||
*
|
||||
* @param array $labels The array of x labels to add
|
||||
*/
|
||||
public function add_x_labels($labels)
|
||||
{
|
||||
$this->x_labels = array_merge($this->x_labels, $labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a bottom label
|
||||
*
|
||||
* @param string $label The bottom label to set
|
||||
*/
|
||||
public function set_bottom_label($label)
|
||||
{
|
||||
$this->bottom_label = $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the graph to memory
|
||||
*
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
// Get our max's and min's
|
||||
$asorted = $this->points;
|
||||
sort($asorted, SORT_NUMERIC);
|
||||
$min = $asorted[0];
|
||||
$max = $asorted[count($asorted)-1];
|
||||
|
||||
// Scale based on how many points we need to shove into 930 pixels of width
|
||||
$x_delta = $this->inside_width/count($this->points);
|
||||
|
||||
// Scale our y axis to 220 pixels
|
||||
$y_scale_factor = ($max-$min)/$this->inside_height;
|
||||
|
||||
// Get our Y initial
|
||||
$y_initial = $this->inside_y+$this->inside_height;
|
||||
|
||||
// Get our scale for finding our points of reference to place our x axis labels
|
||||
$x_label_scale = ceil(count($this->points)/20);
|
||||
$x_label_points = array();
|
||||
$next_y_scaled = 0;
|
||||
|
||||
foreach($this->points as $x => $y)
|
||||
{
|
||||
if(($x_label_scale == 0 || (($x+1) % $x_label_scale) == 0) && $x != 0)
|
||||
{
|
||||
$x_label_points[] = $x;
|
||||
|
||||
imagedashedline($this->im, $this->inside_x+($x_delta*$x), 30, $this->inside_x+($x_delta*$x), $y_initial, $this->color(185, 185, 185));
|
||||
|
||||
imagefilledellipse($this->im, $this->inside_x+($x_delta*$x), $y_initial-$next_y_scaled+0.5, 8, 8, $this->color(84, 92, 209));
|
||||
}
|
||||
|
||||
// Look ahead to find our next point, if there is one
|
||||
if(!array_key_exists($x+1, $this->points))
|
||||
{
|
||||
break;
|
||||
}
|
||||
$next_y = $this->points[$x+1];
|
||||
|
||||
if($y_scale_factor == 0)
|
||||
{
|
||||
$y_scaled = $next_y_scaled = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$y_scaled = ($y-$min)/$y_scale_factor;
|
||||
$next_y_scaled = ($next_y-$min)/$y_scale_factor;
|
||||
}
|
||||
|
||||
// Draw our line
|
||||
$this->imagelinethick($this->inside_x+($x_delta*$x), $y_initial-$y_scaled, $this->inside_x+($x_delta*($x+1)), $y_initial-$next_y_scaled, $this->color(84, 92, 209), 3);
|
||||
}
|
||||
|
||||
// Draw our x labels
|
||||
foreach($x_label_points as $x)
|
||||
{
|
||||
$label = $this->x_labels[$x];
|
||||
$text_width = imagefontwidth(2)*strlen($label);
|
||||
$x = $this->inside_x+($x_delta*$x)-($text_width/2);
|
||||
|
||||
imagestring($this->im, 2, $x, $y_initial+5, $label, $this->color(0, 0, 0));
|
||||
}
|
||||
|
||||
// Draw our bottom label
|
||||
imagestring($this->im, 2, ($this->img_width / 2), $y_initial+25, $this->bottom_label, $this->color(0, 0, 0));
|
||||
|
||||
if($max > 4)
|
||||
{
|
||||
// Draw our y labels
|
||||
for($i = 1; $i < 4; ++$i)
|
||||
{
|
||||
$y_value = $this->inside_y+(($this->inside_height/4)*$i);
|
||||
imagestring($this->im, 2, 5, $y_value-7, my_number_format(round($min+(($max-$min)/4)*(4-$i))), $this->color(0, 0, 0));
|
||||
}
|
||||
}
|
||||
imagestring($this->im, 2, 5, $this->inside_y+$this->inside_height-7, my_number_format($min), $this->color(0, 0, 0));
|
||||
imagestring($this->im, 2, 5, $this->inside_y-7, my_number_format($max), $this->color(0, 0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the graph to the screen in PNG format
|
||||
*
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
// Output the image
|
||||
header("Content-type: image/png");
|
||||
imagepng($this->im);
|
||||
imagedestroy($this->im);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
242
webroot/forum/inc/class_language.php
Normal file
242
webroot/forum/inc/class_language.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
class MyLanguage
|
||||
{
|
||||
|
||||
/**
|
||||
* The path to the languages folder.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $path;
|
||||
|
||||
/**
|
||||
* The language we are using.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language;
|
||||
|
||||
/**
|
||||
* The fallback language we are using.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $fallback = 'english';
|
||||
|
||||
/**
|
||||
* Information about the current language.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $settings;
|
||||
|
||||
/**
|
||||
* Set the path for the language folder.
|
||||
*
|
||||
* @param string $path The path to the language folder.
|
||||
*/
|
||||
function set_path($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific language exists.
|
||||
*
|
||||
* @param string $language The language to check for.
|
||||
* @return boolean True when exists, false when does not exist.
|
||||
*/
|
||||
function language_exists($language)
|
||||
{
|
||||
$language = preg_replace("#[^a-z0-9\-_]#i", "", $language);
|
||||
if(file_exists($this->path."/".$language.".php"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the language for an area.
|
||||
*
|
||||
* @param string $language The language to use.
|
||||
* @param string $area The area to set the language for.
|
||||
*/
|
||||
function set_language($language="", $area="user")
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
$language = preg_replace("#[^a-z0-9\-_]#i", "", $language);
|
||||
|
||||
// Use the board's default language
|
||||
if($language == "")
|
||||
{
|
||||
$language = $mybb->settings['bblanguage'];
|
||||
}
|
||||
|
||||
// Check if the language exists.
|
||||
if(!$this->language_exists($language))
|
||||
{
|
||||
die("Language $language ($this->path/$language) is not installed");
|
||||
}
|
||||
|
||||
$this->language = $language;
|
||||
require $this->path."/".$language.".php";
|
||||
$this->settings = $langinfo;
|
||||
|
||||
// Load the admin language files as well, if needed.
|
||||
if($area == "admin")
|
||||
{
|
||||
if(!is_dir($this->path."/".$language."/{$area}"))
|
||||
{
|
||||
if(!is_dir($this->path."/".$mybb->settings['cplanguage']."/{$area}"))
|
||||
{
|
||||
if(!is_dir($this->path."/english/{$area}"))
|
||||
{
|
||||
die("Your forum does not contain an Administration set. Please reupload the english language administration pack.");
|
||||
}
|
||||
else
|
||||
{
|
||||
$language = "english";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$language = $mybb->settings['cplanguage'];
|
||||
}
|
||||
}
|
||||
$this->language = $language."/{$area}";
|
||||
$this->fallback = $this->fallback."/{$area}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the language variables for a section.
|
||||
*
|
||||
* @param string $section The section name.
|
||||
* @param boolean $isdatahandler Is this a datahandler?
|
||||
* @param boolean $supress_error supress the error if the file doesn't exist?
|
||||
*/
|
||||
function load($section, $isdatahandler=false, $supress_error=false)
|
||||
{
|
||||
// Assign language variables.
|
||||
// Datahandlers are never in admin lang directory.
|
||||
if($isdatahandler === true)
|
||||
{
|
||||
$lfile = $this->path."/".str_replace('/admin', '', $this->language)."/".$section.".lang.php";
|
||||
}
|
||||
else
|
||||
{
|
||||
$lfile = $this->path."/".$this->language."/".$section.".lang.php";
|
||||
}
|
||||
|
||||
if(file_exists($lfile))
|
||||
{
|
||||
require_once $lfile;
|
||||
}
|
||||
elseif(file_exists($this->path."/".$this->fallback."/".$section.".lang.php"))
|
||||
{
|
||||
require_once $this->path."/".$this->fallback."/".$section.".lang.php";
|
||||
}
|
||||
else
|
||||
{
|
||||
if($supress_error != true)
|
||||
{
|
||||
die("$lfile does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
// We must unite and protect our language variables!
|
||||
$lang_keys_ignore = array('language', 'path', 'settings');
|
||||
|
||||
if(isset($l) && is_array($l))
|
||||
{
|
||||
foreach($l as $key => $val)
|
||||
{
|
||||
if((empty($this->$key) || $this->$key != $val) && !in_array($key, $lang_keys_ignore))
|
||||
{
|
||||
$this->$key = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function sprintf($string)
|
||||
{
|
||||
$arg_list = func_get_args();
|
||||
$num_args = count($arg_list);
|
||||
|
||||
for($i = 1; $i < $num_args; $i++)
|
||||
{
|
||||
$string = str_replace('{'.$i.'}', $arg_list[$i], $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the language variables for a section.
|
||||
*
|
||||
* @param boolean $admin Admin variables when true, user when false.
|
||||
* @return array The language variables.
|
||||
*/
|
||||
function get_languages($admin=false)
|
||||
{
|
||||
$dir = @opendir($this->path);
|
||||
while($lang = readdir($dir))
|
||||
{
|
||||
$ext = my_strtolower(get_extension($lang));
|
||||
if($lang != "." && $lang != ".." && $ext == "php")
|
||||
{
|
||||
$lname = str_replace(".".$ext, "", $lang);
|
||||
require $this->path."/".$lang;
|
||||
if(!$admin || ($admin && $langinfo['admin']))
|
||||
{
|
||||
$languages[$lname] = $langinfo['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ksort($languages);
|
||||
return $languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse contents for language variables.
|
||||
*
|
||||
* @param string $contents The contents to parse.
|
||||
* @return string The parsed contents.
|
||||
*/
|
||||
function parse($contents)
|
||||
{
|
||||
$contents = preg_replace_callback("#<lang:([a-zA-Z0-9_]+)>#", array($this, 'parse_replace'), $contents);
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace content with language variable.
|
||||
*
|
||||
* @param array $matches Matches.
|
||||
* @return string Language variable.
|
||||
*/
|
||||
function parse_replace($matches)
|
||||
{
|
||||
return $this->{$matches[1]};
|
||||
}
|
||||
}
|
||||
438
webroot/forum/inc/class_mailhandler.php
Normal file
438
webroot/forum/inc/class_mailhandler.php
Normal file
@@ -0,0 +1,438 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base mail handler class.
|
||||
*/
|
||||
class MailHandler
|
||||
{
|
||||
/**
|
||||
* Which email it should send to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $to;
|
||||
|
||||
/**
|
||||
* 1/0 value weather it should show errors or not.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $show_errors = 1;
|
||||
|
||||
/**
|
||||
* Who it is from.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $from;
|
||||
|
||||
/**
|
||||
* Full from string including name in format "name" <email>
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $from_named;
|
||||
|
||||
/**
|
||||
* Who the email should return to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $return_email;
|
||||
|
||||
/**
|
||||
* The subject of mail.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $subject;
|
||||
|
||||
/**
|
||||
* The unaltered subject of mail.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $orig_subject;
|
||||
|
||||
/**
|
||||
* The message of the mail.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* The headers of the mail.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $headers;
|
||||
|
||||
/**
|
||||
* The charset of the mail.
|
||||
*
|
||||
* @var string
|
||||
* @default utf-8
|
||||
*/
|
||||
public $charset = "utf-8";
|
||||
|
||||
/**
|
||||
* The currently used delimiter new lines.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delimiter = "\r\n";
|
||||
|
||||
/**
|
||||
* How it should parse the email (HTML or plain text?)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $parse_format = 'text';
|
||||
|
||||
/**
|
||||
* The last received response from the SMTP server.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $data = '';
|
||||
|
||||
/**
|
||||
* The last received response code from the SMTP server.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $code = 0;
|
||||
|
||||
/**
|
||||
* Selects between AdminEmail and ReturnEmail, dependant on if ReturnEmail is filled.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function get_from_email()
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
if(trim($mybb->settings['returnemail']))
|
||||
{
|
||||
$email = $mybb->settings['returnemail'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$email = $mybb->settings['adminemail'];
|
||||
}
|
||||
|
||||
return $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the whole mail.
|
||||
* To be used by the different email classes later.
|
||||
*
|
||||
* @param string $to to email.
|
||||
* @param string $subject subject of email.
|
||||
* @param string $message message of email.
|
||||
* @param string $from from email.
|
||||
* @param string $charset charset of email.
|
||||
* @param string $headers headers of email.
|
||||
* @param string $format format of the email (HTML, plain text, or both?).
|
||||
* @param string $message_text plain text version of the email.
|
||||
* @param string $return_email the return email address.
|
||||
*/
|
||||
function build_message($to, $subject, $message, $from="", $charset="", $headers="", $format="text", $message_text="", $return_email="")
|
||||
{
|
||||
global $parser, $lang, $mybb;
|
||||
|
||||
$this->message = '';
|
||||
$this->headers = $headers;
|
||||
|
||||
if($from)
|
||||
{
|
||||
$this->from = $from;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->from = $this->get_from_email();
|
||||
$this->from_named = '"'.$this->utf8_encode($mybb->settings['bbname']).'"';
|
||||
$this->from_named .= " <".$this->from.">";
|
||||
}
|
||||
|
||||
if($return_email)
|
||||
{
|
||||
$this->return_email = $return_email;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->return_email = "";
|
||||
$this->return_email = $this->get_from_email();
|
||||
}
|
||||
|
||||
$this->set_to($to);
|
||||
$this->set_subject($subject);
|
||||
|
||||
if($charset)
|
||||
{
|
||||
$this->set_charset($charset);
|
||||
}
|
||||
|
||||
$this->parse_format = $format;
|
||||
$this->set_common_headers();
|
||||
$this->set_message($message, $message_text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the charset.
|
||||
*
|
||||
* @param string $charset charset
|
||||
*/
|
||||
function set_charset($charset)
|
||||
{
|
||||
global $lang;
|
||||
|
||||
if(empty($charset))
|
||||
{
|
||||
$this->charset = $lang->settings['charset'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->charset = $charset;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and formats the email message.
|
||||
*
|
||||
* @param string $message message
|
||||
* @param string $message_text
|
||||
*/
|
||||
function set_message($message, $message_text="")
|
||||
{
|
||||
$message = $this->cleanup_crlf($message);
|
||||
|
||||
if($message_text)
|
||||
{
|
||||
$message_text = $this->cleanup_crlf($message_text);
|
||||
}
|
||||
|
||||
if($this->parse_format == "html" || $this->parse_format == "both")
|
||||
{
|
||||
$this->set_html_headers($message, $message_text);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->set_plain_headers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and formats the email subject.
|
||||
*
|
||||
* @param string $subject
|
||||
*/
|
||||
function set_subject($subject)
|
||||
{
|
||||
$this->orig_subject = $this->cleanup($subject);
|
||||
$this->subject = $this->utf8_encode($this->orig_subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and formats the recipient address.
|
||||
*
|
||||
* @param string $to
|
||||
*/
|
||||
function set_to($to)
|
||||
{
|
||||
$to = $this->cleanup($to);
|
||||
|
||||
$this->to = $this->cleanup($to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the plain headers, text/plain
|
||||
*/
|
||||
function set_plain_headers()
|
||||
{
|
||||
$this->headers .= "Content-Type: text/plain; charset={$this->charset}{$this->delimiter}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alternative headers, text/html and text/plain.
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $message_text
|
||||
*/
|
||||
function set_html_headers($message, $message_text="")
|
||||
{
|
||||
if(!$message_text && $this->parse_format == 'both')
|
||||
{
|
||||
$message_text = strip_tags($message);
|
||||
}
|
||||
|
||||
if($this->parse_format == 'both')
|
||||
{
|
||||
$mime_boundary = "=_NextPart".md5(TIME_NOW);
|
||||
|
||||
$this->headers .= "Content-Type: multipart/alternative; boundary=\"{$mime_boundary}\"{$this->delimiter}";
|
||||
$this->message = "This is a multi-part message in MIME format.{$this->delimiter}{$this->delimiter}";
|
||||
|
||||
$this->message .= "--{$mime_boundary}{$this->delimiter}";
|
||||
$this->message .= "Content-Type: text/plain; charset=\"{$this->charset}\"{$this->delimiter}";
|
||||
$this->message .= "Content-Transfer-Encoding: 8bit{$this->delimiter}{$this->delimiter}";
|
||||
$this->message .= $message_text."{$this->delimiter}{$this->delimiter}";
|
||||
|
||||
$this->message .= "--{$mime_boundary}{$this->delimiter}";
|
||||
|
||||
$this->message .= "Content-Type: text/html; charset=\"{$this->charset}\"{$this->delimiter}";
|
||||
$this->message .= "Content-Transfer-Encoding: 8bit{$this->delimiter}{$this->delimiter}";
|
||||
$this->message .= $message."{$this->delimiter}{$this->delimiter}";
|
||||
|
||||
$this->message .= "--{$mime_boundary}--{$this->delimiter}{$this->delimiter}";
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->headers .= "Content-Type: text/html; charset=\"{$this->charset}\"{$this->delimiter}";
|
||||
$this->headers .= "Content-Transfer-Encoding: 8bit{$this->delimiter}{$this->delimiter}";
|
||||
$this->message = $message."{$this->delimiter}{$this->delimiter}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the common headers.
|
||||
*/
|
||||
function set_common_headers()
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
// Build mail headers
|
||||
$this->headers .= "From: {$this->from_named}{$this->delimiter}";
|
||||
|
||||
if($this->return_email)
|
||||
{
|
||||
$this->headers .= "Return-Path: {$this->return_email}{$this->delimiter}";
|
||||
$this->headers .= "Reply-To: {$this->return_email}{$this->delimiter}";
|
||||
}
|
||||
|
||||
if(isset($_SERVER['SERVER_NAME']))
|
||||
{
|
||||
$http_host = $_SERVER['SERVER_NAME'];
|
||||
}
|
||||
else if(isset($_SERVER['HTTP_HOST']))
|
||||
{
|
||||
$http_host = $_SERVER['HTTP_HOST'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$http_host = "unknown.local";
|
||||
}
|
||||
|
||||
$msg_id = md5(uniqid(TIME_NOW, true)) . "@" . $http_host;
|
||||
|
||||
if($mybb->settings['mail_message_id'])
|
||||
{
|
||||
$this->headers .= "Message-ID: <{$msg_id}>{$this->delimiter}";
|
||||
}
|
||||
$this->headers .= "Content-Transfer-Encoding: 8bit{$this->delimiter}";
|
||||
$this->headers .= "X-Priority: 3{$this->delimiter}";
|
||||
$this->headers .= "X-Mailer: MyBB{$this->delimiter}";
|
||||
$this->headers .= "MIME-Version: 1.0{$this->delimiter}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a fatal error message to the database.
|
||||
*
|
||||
* @param string $error The error message
|
||||
*/
|
||||
function fatal_error($error)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$mail_error = array(
|
||||
"subject" => $db->escape_string($this->orig_subject),
|
||||
"message" => $db->escape_string($this->message),
|
||||
"toaddress" => $db->escape_string($this->to),
|
||||
"fromaddress" => $db->escape_string($this->from),
|
||||
"dateline" => TIME_NOW,
|
||||
"error" => $db->escape_string($error),
|
||||
"smtperror" => $db->escape_string($this->data),
|
||||
"smtpcode" => (int)$this->code
|
||||
);
|
||||
$db->insert_query("mailerrors", $mail_error);
|
||||
|
||||
// Another neat feature would be the ability to notify the site administrator via email - but wait, with email down, how do we do that? How about private message and hope the admin checks their PMs?
|
||||
}
|
||||
|
||||
/**
|
||||
* Rids pesky characters from subjects, recipients, from addresses etc (prevents mail injection too)
|
||||
*
|
||||
* @param string $string The string being checked
|
||||
* @return string The cleaned string
|
||||
*/
|
||||
function cleanup($string)
|
||||
{
|
||||
$string = str_replace(array("\r", "\n", "\r\n"), "", $string);
|
||||
$string = trim($string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts message text to suit the correct delimiter
|
||||
* See dev.mybb.com/issues/1735 (Jorge Oliveira)
|
||||
*
|
||||
* @param string $text The text being converted
|
||||
* @return string The converted string
|
||||
*/
|
||||
function cleanup_crlf($text)
|
||||
{
|
||||
$text = str_replace("\r\n", "\n", $text);
|
||||
$text = str_replace("\r", "\n", $text);
|
||||
$text = str_replace("\n", "\r\n", $text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a string based on the character set enabled. Used to encode subjects
|
||||
* and recipients in email messages going out so that they show up correctly
|
||||
* in email clients.
|
||||
*
|
||||
* @param string $string The string to be encoded.
|
||||
* @return string The encoded string.
|
||||
*/
|
||||
function utf8_encode($string)
|
||||
{
|
||||
if(strtolower($this->charset) == 'utf-8' && preg_match('/[^\x20-\x7E]/', $string))
|
||||
{
|
||||
$chunk_size = 47; // Derived from floor((75 - strlen("=?UTF-8?B??=")) * 0.75);
|
||||
$len = strlen($string);
|
||||
$output = '';
|
||||
$pos = 0;
|
||||
|
||||
while($pos < $len)
|
||||
{
|
||||
$newpos = min($pos + $chunk_size, $len);
|
||||
|
||||
while(ord($string[$newpos]) >= 0x80 && ord($string[$newpos]) < 0xC0)
|
||||
{
|
||||
// Reduce len until it's safe to split UTF-8.
|
||||
$newpos--;
|
||||
}
|
||||
|
||||
$chunk = substr($string, $pos, $newpos - $pos);
|
||||
$pos = $newpos;
|
||||
|
||||
$output .= " =?UTF-8?B?".base64_encode($chunk)."?=\n";
|
||||
}
|
||||
return trim($output);
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
3773
webroot/forum/inc/class_moderation.php
Normal file
3773
webroot/forum/inc/class_moderation.php
Normal file
File diff suppressed because it is too large
Load Diff
1872
webroot/forum/inc/class_parser.php
Normal file
1872
webroot/forum/inc/class_parser.php
Normal file
File diff suppressed because it is too large
Load Diff
248
webroot/forum/inc/class_plugins.php
Normal file
248
webroot/forum/inc/class_plugins.php
Normal file
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*/
|
||||
|
||||
class pluginSystem
|
||||
{
|
||||
/**
|
||||
* The hooks to which plugins can be attached.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $hooks;
|
||||
/**
|
||||
* The current hook which we're in (if any)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $current_hook;
|
||||
|
||||
/**
|
||||
* Load all plugins.
|
||||
*/
|
||||
function load()
|
||||
{
|
||||
global $cache, $plugins;
|
||||
|
||||
$plugin_list = $cache->read("plugins");
|
||||
if(!empty($plugin_list['active']) && is_array($plugin_list['active']))
|
||||
{
|
||||
foreach($plugin_list['active'] as $plugin)
|
||||
{
|
||||
if($plugin != "" && file_exists(MYBB_ROOT."inc/plugins/".$plugin.".php"))
|
||||
{
|
||||
require_once MYBB_ROOT."inc/plugins/".$plugin.".php";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a hook onto which a plugin can be attached.
|
||||
*
|
||||
* @param string $hook The hook name.
|
||||
* @param array|string $function The function of this hook.
|
||||
* @param int $priority The priority this hook has.
|
||||
* @param string $file The optional file belonging to this hook.
|
||||
* @return boolean Whether the hook was added.
|
||||
*/
|
||||
function add_hook($hook, $function, $priority=10, $file="")
|
||||
{
|
||||
if(is_array($function))
|
||||
{
|
||||
if(!count($function) == 2)
|
||||
{ // must be an array of two items!
|
||||
return false;
|
||||
}
|
||||
|
||||
if(is_string($function[0]))
|
||||
{
|
||||
// Static class method
|
||||
$method_representation = sprintf('%s::%s', $function[0], $function[1]);
|
||||
}
|
||||
elseif(is_object($function[0]))
|
||||
{
|
||||
// Instance class method
|
||||
$method_representation = sprintf('%s->%s', spl_object_hash($function[0]), $function[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown array type
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if we already have this hook running at this priority
|
||||
if(!empty($this->hooks[$hook][$priority][$method_representation]) && is_array($this->hooks[$hook][$priority][$method_representation]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add the hook
|
||||
$this->hooks[$hook][$priority][$method_representation] = array(
|
||||
'class_method' => $function,
|
||||
'file' => $file
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check to see if we already have this hook running at this priority
|
||||
if(!empty($this->hooks[$hook][$priority][$function]) && is_array($this->hooks[$hook][$priority][$function]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add the hook
|
||||
$this->hooks[$hook][$priority][$function] = array(
|
||||
'function' => $function,
|
||||
'file' => $file
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the hooks that have plugins.
|
||||
*
|
||||
* @param string $hook The name of the hook that is run.
|
||||
* @param mixed $arguments The argument for the hook that is run. The passed value MUST be a variable
|
||||
* @return mixed The arguments for the hook.
|
||||
*/
|
||||
function run_hooks($hook, &$arguments="")
|
||||
{
|
||||
if(!isset($this->hooks[$hook]) || !is_array($this->hooks[$hook]))
|
||||
{
|
||||
return $arguments;
|
||||
}
|
||||
$this->current_hook = $hook;
|
||||
ksort($this->hooks[$hook]);
|
||||
foreach($this->hooks[$hook] as $priority => $hooks)
|
||||
{
|
||||
if(is_array($hooks))
|
||||
{
|
||||
foreach($hooks as $key => $hook)
|
||||
{
|
||||
if($hook['file'])
|
||||
{
|
||||
require_once $hook['file'];
|
||||
}
|
||||
|
||||
if(array_key_exists('class_method', $hook))
|
||||
{
|
||||
$return_args = call_user_func_array($hook['class_method'], array(&$arguments));
|
||||
}
|
||||
else
|
||||
{
|
||||
$func = $hook['function'];
|
||||
|
||||
$return_args = $func($arguments);
|
||||
}
|
||||
|
||||
if($return_args)
|
||||
{
|
||||
$arguments = $return_args;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->current_hook = '';
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific hook.
|
||||
*
|
||||
* @param string $hook The name of the hook.
|
||||
* @param array|string $function The function of the hook.
|
||||
* @param string $file The filename of the plugin.
|
||||
* @param int $priority The priority of the hook.
|
||||
* @return bool Whether the hook was removed successfully.
|
||||
*/
|
||||
function remove_hook($hook, $function, $file="", $priority=10)
|
||||
{
|
||||
if(is_array($function))
|
||||
{
|
||||
if(is_string($function[0]))
|
||||
{ // Static class method
|
||||
$method_representation = sprintf('%s::%s', $function[0], $function[1]);
|
||||
}
|
||||
elseif(is_object($function[0]))
|
||||
{ // Instance class method
|
||||
$method_representation = sprintf('%s->%s', get_class($function[0]), $function[1]);
|
||||
}
|
||||
else
|
||||
{ // Unknown array type
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isset($this->hooks[$hook][$priority][$method_representation]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
unset($this->hooks[$hook][$priority][$method_representation]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check to see if we don't already have this hook running at this priority
|
||||
if(!isset($this->hooks[$hook][$priority][$function]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
unset($this->hooks[$hook][$priority][$function]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes if a particular plugin is compatible with this version of MyBB.
|
||||
*
|
||||
* @param string $plugin The name of the plugin.
|
||||
* @return boolean TRUE if compatible, FALSE if incompatible.
|
||||
*/
|
||||
function is_compatible($plugin)
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
// Ignore potentially missing plugins.
|
||||
if(!file_exists(MYBB_ROOT."inc/plugins/".$plugin.".php"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
require_once MYBB_ROOT."inc/plugins/".$plugin.".php";
|
||||
|
||||
$info_func = "{$plugin}_info";
|
||||
if(!function_exists($info_func))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$plugin_info = $info_func();
|
||||
|
||||
// No compatibility set or compatibility = * - assume compatible
|
||||
if(!$plugin_info['compatibility'] || $plugin_info['compatibility'] == "*")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
$compatibility = explode(",", $plugin_info['compatibility']);
|
||||
foreach($compatibility as $version)
|
||||
{
|
||||
$version = trim($version);
|
||||
$version = str_replace("*", ".+", preg_quote($version));
|
||||
$version = str_replace("\.+", ".+", $version);
|
||||
if(preg_match("#{$version}#i", $mybb->version_code))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing matches
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
575
webroot/forum/inc/class_session.php
Normal file
575
webroot/forum/inc/class_session.php
Normal file
@@ -0,0 +1,575 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
class session
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $sid = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $uid = 0;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $ipaddress = '';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $packedip = '';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $useragent = '';
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $is_spider = false;
|
||||
|
||||
/**
|
||||
* Initialize a session
|
||||
*/
|
||||
function init()
|
||||
{
|
||||
global $db, $mybb, $cache;
|
||||
|
||||
// Get our visitor's IP.
|
||||
$this->ipaddress = get_ip();
|
||||
$this->packedip = my_inet_pton($this->ipaddress);
|
||||
|
||||
// Find out the user agent.
|
||||
$this->useragent = $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
// Attempt to find a session id in the cookies.
|
||||
if(isset($mybb->cookies['sid']) && !defined('IN_UPGRADE'))
|
||||
{
|
||||
$sid = $db->escape_string($mybb->cookies['sid']);
|
||||
// Load the session
|
||||
$query = $db->simple_select("sessions", "*", "sid='{$sid}' AND ip=".$db->escape_binary($this->packedip));
|
||||
$session = $db->fetch_array($query);
|
||||
if($session['sid'])
|
||||
{
|
||||
$this->sid = $session['sid'];
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a valid session id and user id, load that users session.
|
||||
if(!empty($mybb->cookies['mybbuser']))
|
||||
{
|
||||
$logon = explode("_", $mybb->cookies['mybbuser'], 2);
|
||||
$this->load_user($logon[0], $logon[1]);
|
||||
}
|
||||
|
||||
// If no user still, then we have a guest.
|
||||
if(!isset($mybb->user['uid']))
|
||||
{
|
||||
// Detect if this guest is a search engine spider. (bots don't get a cookied session ID so we first see if that's set)
|
||||
if(!$this->sid)
|
||||
{
|
||||
$spiders = $cache->read("spiders");
|
||||
if(is_array($spiders))
|
||||
{
|
||||
foreach($spiders as $spider)
|
||||
{
|
||||
if(my_strpos(my_strtolower($this->useragent), my_strtolower($spider['useragent'])) !== false)
|
||||
{
|
||||
$this->load_spider($spider['sid']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Still nothing? JUST A GUEST!
|
||||
if(!$this->is_spider)
|
||||
{
|
||||
$this->load_guest();
|
||||
}
|
||||
}
|
||||
|
||||
// As a token of our appreciation for getting this far (and they aren't a spider), give the user a cookie
|
||||
if($this->sid && (!isset($mybb->cookies['sid']) || $mybb->cookies['sid'] != $this->sid) && $this->is_spider != true)
|
||||
{
|
||||
my_setcookie("sid", $this->sid, -1, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a user via the user credentials.
|
||||
*
|
||||
* @param int $uid The user id.
|
||||
* @param string $loginkey The user's loginkey.
|
||||
* @return bool
|
||||
*/
|
||||
function load_user($uid, $loginkey='')
|
||||
{
|
||||
global $mybb, $db, $time, $lang, $mybbgroups, $cache;
|
||||
|
||||
// Read the banned cache
|
||||
$bannedcache = $cache->read("banned");
|
||||
|
||||
// If the banned cache doesn't exist, update it and re-read it
|
||||
if(!is_array($bannedcache))
|
||||
{
|
||||
$cache->update_banned();
|
||||
$bannedcache = $cache->read("banned");
|
||||
}
|
||||
|
||||
$uid = (int)$uid;
|
||||
$query = $db->query("
|
||||
SELECT u.*, f.*
|
||||
FROM ".TABLE_PREFIX."users u
|
||||
LEFT JOIN ".TABLE_PREFIX."userfields f ON (f.ufid=u.uid)
|
||||
WHERE u.uid='$uid'
|
||||
LIMIT 1
|
||||
");
|
||||
$mybb->user = $db->fetch_array($query);
|
||||
|
||||
if(!empty($bannedcache[$uid]))
|
||||
{
|
||||
$banned_user = $bannedcache[$uid];
|
||||
$mybb->user['bandate'] = $banned_user['dateline'];
|
||||
$mybb->user['banlifted'] = $banned_user['lifted'];
|
||||
$mybb->user['banoldgroup'] = $banned_user['oldgroup'];
|
||||
$mybb->user['banolddisplaygroup'] = $banned_user['olddisplaygroup'];
|
||||
$mybb->user['banoldadditionalgroups'] = $banned_user['oldadditionalgroups'];
|
||||
}
|
||||
|
||||
// Check the password if we're not using a session
|
||||
if(empty($loginkey) || $loginkey !== $mybb->user['loginkey'] || !$mybb->user['uid'])
|
||||
{
|
||||
unset($mybb->user);
|
||||
$this->uid = 0;
|
||||
return false;
|
||||
}
|
||||
$this->uid = $mybb->user['uid'];
|
||||
|
||||
// Set the logout key for this user
|
||||
$mybb->user['logoutkey'] = md5($mybb->user['loginkey']);
|
||||
|
||||
// Sort out the private message count for this user.
|
||||
if(($mybb->user['totalpms'] == -1 || $mybb->user['unreadpms'] == -1) && $mybb->settings['enablepms'] != 0) // Forced recount
|
||||
{
|
||||
$update = 0;
|
||||
if($mybb->user['totalpms'] == -1)
|
||||
{
|
||||
$update += 1;
|
||||
}
|
||||
if($mybb->user['unreadpms'] == -1)
|
||||
{
|
||||
$update += 2;
|
||||
}
|
||||
|
||||
require_once MYBB_ROOT."inc/functions_user.php";
|
||||
$pmcount = update_pm_count('', $update);
|
||||
if(is_array($pmcount))
|
||||
{
|
||||
$mybb->user = array_merge($mybb->user, $pmcount);
|
||||
}
|
||||
}
|
||||
$mybb->user['pms_total'] = $mybb->user['totalpms'];
|
||||
$mybb->user['pms_unread'] = $mybb->user['unreadpms'];
|
||||
|
||||
if($mybb->user['lastip'] != $this->packedip && array_key_exists('lastip', $mybb->user) && !defined('IN_UPGRADE'))
|
||||
{
|
||||
$lastip_add = ", lastip=".$db->escape_binary($this->packedip);
|
||||
}
|
||||
else
|
||||
{
|
||||
$lastip_add = '';
|
||||
}
|
||||
|
||||
// If the last visit was over 900 seconds (session time out) ago then update lastvisit.
|
||||
$time = TIME_NOW;
|
||||
if($time - $mybb->user['lastactive'] > 900)
|
||||
{
|
||||
$db->shutdown_query("UPDATE ".TABLE_PREFIX."users SET lastvisit='{$mybb->user['lastactive']}', lastactive='$time'{$lastip_add} WHERE uid='{$mybb->user['uid']}'");
|
||||
$mybb->user['lastvisit'] = $mybb->user['lastactive'];
|
||||
require_once MYBB_ROOT."inc/functions_user.php";
|
||||
update_pm_count('', 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
$timespent = TIME_NOW - $mybb->user['lastactive'];
|
||||
$db->shutdown_query("UPDATE ".TABLE_PREFIX."users SET lastactive='$time', timeonline=timeonline+$timespent{$lastip_add} WHERE uid='{$mybb->user['uid']}'");
|
||||
}
|
||||
|
||||
// Sort out the language and forum preferences.
|
||||
if($mybb->user['language'] && $lang->language_exists($mybb->user['language']))
|
||||
{
|
||||
$mybb->settings['bblanguage'] = $mybb->user['language'];
|
||||
}
|
||||
if($mybb->user['dateformat'] != 0 && $mybb->user['dateformat'] != '')
|
||||
{
|
||||
global $date_formats;
|
||||
if($date_formats[$mybb->user['dateformat']])
|
||||
{
|
||||
$mybb->settings['dateformat'] = $date_formats[$mybb->user['dateformat']];
|
||||
}
|
||||
}
|
||||
|
||||
// Choose time format.
|
||||
if($mybb->user['timeformat'] != 0 && $mybb->user['timeformat'] != '')
|
||||
{
|
||||
global $time_formats;
|
||||
if($time_formats[$mybb->user['timeformat']])
|
||||
{
|
||||
$mybb->settings['timeformat'] = $time_formats[$mybb->user['timeformat']];
|
||||
}
|
||||
}
|
||||
|
||||
// Find out the threads per page preference.
|
||||
if($mybb->user['tpp'])
|
||||
{
|
||||
$mybb->settings['threadsperpage'] = $mybb->user['tpp'];
|
||||
}
|
||||
|
||||
// Find out the posts per page preference.
|
||||
if($mybb->user['ppp'])
|
||||
{
|
||||
$mybb->settings['postsperpage'] = $mybb->user['ppp'];
|
||||
}
|
||||
|
||||
// Does this user prefer posts in classic mode?
|
||||
if($mybb->user['classicpostbit'])
|
||||
{
|
||||
$mybb->settings['postlayout'] = 'classic';
|
||||
}
|
||||
else
|
||||
{
|
||||
$mybb->settings['postlayout'] = 'horizontal';
|
||||
}
|
||||
|
||||
// Check if this user is currently banned and if we have to lift it.
|
||||
if(!empty($mybb->user['bandate']) && (isset($mybb->user['banlifted']) && !empty($mybb->user['banlifted'])) && $mybb->user['banlifted'] < $time) // hmmm...bad user... how did you get banned =/
|
||||
{
|
||||
// must have been good.. bans up :D
|
||||
$db->shutdown_query("UPDATE ".TABLE_PREFIX."users SET usergroup='".(int)$mybb->user['banoldgroup']."', additionalgroups='".$mybb->user['banoldadditionalgroups']."', displaygroup='".(int)$mybb->user['banolddisplaygroup']."' WHERE uid='".$mybb->user['uid']."'");
|
||||
$db->shutdown_query("DELETE FROM ".TABLE_PREFIX."banned WHERE uid='".$mybb->user['uid']."'");
|
||||
// we better do this..otherwise they have dodgy permissions
|
||||
$mybb->user['usergroup'] = $mybb->user['banoldgroup'];
|
||||
$mybb->user['displaygroup'] = $mybb->user['banolddisplaygroup'];
|
||||
$mybb->user['additionalgroups'] = $mybb->user['banoldadditionalgroups'];
|
||||
$cache->update_banned();
|
||||
|
||||
$mybbgroups = $mybb->user['usergroup'];
|
||||
if($mybb->user['additionalgroups'])
|
||||
{
|
||||
$mybbgroups .= ','.$mybb->user['additionalgroups'];
|
||||
}
|
||||
}
|
||||
else if(!empty($mybb->user['bandate']) && (empty($mybb->user['banlifted']) || !empty($mybb->user['banlifted']) && $mybb->user['banlifted'] > $time))
|
||||
{
|
||||
$mybbgroups = $mybb->user['usergroup'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gather a full permission set for this user and the groups they are in.
|
||||
$mybbgroups = $mybb->user['usergroup'];
|
||||
if($mybb->user['additionalgroups'])
|
||||
{
|
||||
$mybbgroups .= ','.$mybb->user['additionalgroups'];
|
||||
}
|
||||
}
|
||||
|
||||
$mybb->usergroup = usergroup_permissions($mybbgroups);
|
||||
if(!$mybb->user['displaygroup'])
|
||||
{
|
||||
$mybb->user['displaygroup'] = $mybb->user['usergroup'];
|
||||
}
|
||||
|
||||
$mydisplaygroup = usergroup_displaygroup($mybb->user['displaygroup']);
|
||||
if(is_array($mydisplaygroup))
|
||||
{
|
||||
$mybb->usergroup = array_merge($mybb->usergroup, $mydisplaygroup);
|
||||
}
|
||||
|
||||
if(!$mybb->user['usertitle'])
|
||||
{
|
||||
$mybb->user['usertitle'] = $mybb->usergroup['usertitle'];
|
||||
}
|
||||
|
||||
// Update or create the session.
|
||||
if(!defined("NO_ONLINE") && !defined('IN_UPGRADE'))
|
||||
{
|
||||
if(!empty($this->sid))
|
||||
{
|
||||
$this->update_session($this->sid, $mybb->user['uid']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->create_session($mybb->user['uid']);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a guest user.
|
||||
*
|
||||
*/
|
||||
function load_guest()
|
||||
{
|
||||
global $mybb, $time, $db, $lang;
|
||||
|
||||
// Set up some defaults
|
||||
$time = TIME_NOW;
|
||||
$mybb->user['usergroup'] = 1;
|
||||
$mybb->user['username'] = '';
|
||||
$mybb->user['uid'] = 0;
|
||||
$mybbgroups = 1;
|
||||
$mybb->user['displaygroup'] = 1;
|
||||
|
||||
// Has this user visited before? Lastvisit need updating?
|
||||
if(isset($mybb->cookies['mybb']['lastvisit']))
|
||||
{
|
||||
if(!isset($mybb->cookies['mybb']['lastactive']))
|
||||
{
|
||||
$mybb->user['lastactive'] = $time;
|
||||
$mybb->cookies['mybb']['lastactive'] = $mybb->user['lastactive'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$mybb->user['lastactive'] = (int)$mybb->cookies['mybb']['lastactive'];
|
||||
}
|
||||
if($time - $mybb->cookies['mybb']['lastactive'] > 900)
|
||||
{
|
||||
my_setcookie("mybb[lastvisit]", $mybb->user['lastactive']);
|
||||
$mybb->user['lastvisit'] = $mybb->user['lastactive'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$mybb->user['lastvisit'] = (int)$mybb->cookies['mybb']['lastactive'];
|
||||
}
|
||||
}
|
||||
|
||||
// No last visit cookie, create one.
|
||||
else
|
||||
{
|
||||
my_setcookie("mybb[lastvisit]", $time);
|
||||
$mybb->user['lastvisit'] = $time;
|
||||
}
|
||||
|
||||
// Update last active cookie.
|
||||
my_setcookie("mybb[lastactive]", $time);
|
||||
|
||||
// Gather a full permission set for this guest
|
||||
$mybb->usergroup = usergroup_permissions($mybbgroups);
|
||||
$mydisplaygroup = usergroup_displaygroup($mybb->user['displaygroup']);
|
||||
if(is_array($mydisplaygroup))
|
||||
{
|
||||
$mybb->usergroup = array_merge($mybb->usergroup, $mydisplaygroup);
|
||||
}
|
||||
|
||||
// Update the online data.
|
||||
if(!defined("NO_ONLINE") && !defined('IN_UPGRADE'))
|
||||
{
|
||||
if(!empty($this->sid))
|
||||
{
|
||||
$this->update_session($this->sid);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->create_session();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a search engine spider.
|
||||
*
|
||||
* @param int $spider_id The ID of the search engine spider
|
||||
*/
|
||||
function load_spider($spider_id)
|
||||
{
|
||||
global $mybb, $time, $db, $lang;
|
||||
|
||||
// Fetch the spider preferences from the database
|
||||
$query = $db->simple_select("spiders", "*", "sid='{$spider_id}'");
|
||||
$spider = $db->fetch_array($query);
|
||||
|
||||
// Set up some defaults
|
||||
$time = TIME_NOW;
|
||||
$this->is_spider = true;
|
||||
if($spider['usergroup'])
|
||||
{
|
||||
$mybb->user['usergroup'] = $spider['usergroup'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$mybb->user['usergroup'] = 1;
|
||||
}
|
||||
$mybb->user['username'] = '';
|
||||
$mybb->user['uid'] = 0;
|
||||
$mybb->user['displaygroup'] = $mybb->user['usergroup'];
|
||||
|
||||
// Set spider language
|
||||
if($spider['language'] && $lang->language_exists($spider['language']))
|
||||
{
|
||||
$mybb->settings['bblanguage'] = $spider['language'];
|
||||
}
|
||||
|
||||
// Set spider theme
|
||||
if($spider['theme'])
|
||||
{
|
||||
$mybb->user['style'] = $spider['theme'];
|
||||
}
|
||||
|
||||
// Gather a full permission set for this spider.
|
||||
$mybb->usergroup = usergroup_permissions($mybb->user['usergroup']);
|
||||
$mydisplaygroup = usergroup_displaygroup($mybb->user['displaygroup']);
|
||||
if(is_array($mydisplaygroup))
|
||||
{
|
||||
$mybb->usergroup = array_merge($mybb->usergroup, $mydisplaygroup);
|
||||
}
|
||||
|
||||
// Update spider last minute (only do so on two minute intervals - decrease load for quick spiders)
|
||||
if($spider['lastvisit'] < TIME_NOW-120)
|
||||
{
|
||||
$updated_spider = array(
|
||||
"lastvisit" => TIME_NOW
|
||||
);
|
||||
$db->update_query("spiders", $updated_spider, "sid='{$spider_id}'");
|
||||
}
|
||||
|
||||
// Update the online data.
|
||||
if(!defined("NO_ONLINE") && !defined('IN_UPGRADE'))
|
||||
{
|
||||
$this->sid = "bot=".$spider_id;
|
||||
$this->create_session();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user session.
|
||||
*
|
||||
* @param int $sid The session id.
|
||||
* @param int $uid The user id.
|
||||
*/
|
||||
function update_session($sid, $uid=0)
|
||||
{
|
||||
global $db;
|
||||
|
||||
// Find out what the special locations are.
|
||||
$speciallocs = $this->get_special_locations();
|
||||
if($uid)
|
||||
{
|
||||
$onlinedata['uid'] = $uid;
|
||||
}
|
||||
else
|
||||
{
|
||||
$onlinedata['uid'] = 0;
|
||||
}
|
||||
$onlinedata['time'] = TIME_NOW;
|
||||
|
||||
$onlinedata['location'] = $db->escape_string(substr(get_current_location(), 0, 150));
|
||||
$onlinedata['useragent'] = $db->escape_string(my_substr($this->useragent, 0, 200));
|
||||
|
||||
$onlinedata['location1'] = (int)$speciallocs['1'];
|
||||
$onlinedata['location2'] = (int)$speciallocs['2'];
|
||||
$onlinedata['nopermission'] = 0;
|
||||
$sid = $db->escape_string($sid);
|
||||
|
||||
$db->update_query("sessions", $onlinedata, "sid='{$sid}'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new session.
|
||||
*
|
||||
* @param int $uid The user id to bind the session to.
|
||||
*/
|
||||
function create_session($uid=0)
|
||||
{
|
||||
global $db;
|
||||
$speciallocs = $this->get_special_locations();
|
||||
|
||||
// If there is a proper uid, delete by uid.
|
||||
if($uid > 0)
|
||||
{
|
||||
$db->delete_query("sessions", "uid='{$uid}'");
|
||||
$onlinedata['uid'] = $uid;
|
||||
}
|
||||
// Is a spider - delete all other spider references
|
||||
else if($this->is_spider == true)
|
||||
{
|
||||
$db->delete_query("sessions", "sid='{$this->sid}'");
|
||||
}
|
||||
// Else delete by ip.
|
||||
else
|
||||
{
|
||||
$db->delete_query("sessions", "ip=".$db->escape_binary($this->packedip));
|
||||
$onlinedata['uid'] = 0;
|
||||
}
|
||||
|
||||
// If the user is a search enginge spider, ...
|
||||
if($this->is_spider == true)
|
||||
{
|
||||
$onlinedata['sid'] = $this->sid;
|
||||
}
|
||||
else
|
||||
{
|
||||
$onlinedata['sid'] = md5(random_str(50));
|
||||
}
|
||||
$onlinedata['time'] = TIME_NOW;
|
||||
$onlinedata['ip'] = $db->escape_binary($this->packedip);
|
||||
|
||||
$onlinedata['location'] = $db->escape_string(substr(get_current_location(), 0, 150));
|
||||
$onlinedata['useragent'] = $db->escape_string(my_substr($this->useragent, 0, 200));
|
||||
|
||||
$onlinedata['location1'] = (int)$speciallocs['1'];
|
||||
$onlinedata['location2'] = (int)$speciallocs['2'];
|
||||
$onlinedata['nopermission'] = 0;
|
||||
$db->replace_query("sessions", $onlinedata, "sid", false);
|
||||
$this->sid = $onlinedata['sid'];
|
||||
$this->uid = $onlinedata['uid'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out the special locations.
|
||||
*
|
||||
* @return array Special locations array.
|
||||
*/
|
||||
function get_special_locations()
|
||||
{
|
||||
global $mybb;
|
||||
$array = array('1' => '', '2' => '');
|
||||
if(preg_match("#forumdisplay.php#", $_SERVER['PHP_SELF']) && $mybb->get_input('fid', MyBB::INPUT_INT) > 0 && $mybb->get_input('fid', MyBB::INPUT_INT) < 4294967296)
|
||||
{
|
||||
$array[1] = $mybb->get_input('fid', MyBB::INPUT_INT);
|
||||
$array[2] = '';
|
||||
}
|
||||
elseif(preg_match("#showthread.php#", $_SERVER['PHP_SELF']))
|
||||
{
|
||||
global $db;
|
||||
|
||||
if($mybb->get_input('tid', MyBB::INPUT_INT) > 0 && $mybb->get_input('tid', MyBB::INPUT_INT) < 4294967296)
|
||||
{
|
||||
$array[2] = $mybb->get_input('tid', MyBB::INPUT_INT);
|
||||
}
|
||||
|
||||
// If there is no tid but a pid, trick the system into thinking there was a tid anyway.
|
||||
elseif(isset($mybb->input['pid']) && !empty($mybb->input['pid']))
|
||||
{
|
||||
$options = array(
|
||||
"limit" => 1
|
||||
);
|
||||
$query = $db->simple_select("posts", "tid", "pid=".$mybb->get_input('pid', MyBB::INPUT_INT), $options);
|
||||
$post = $db->fetch_array($query);
|
||||
$array[2] = $post['tid'];
|
||||
}
|
||||
|
||||
$thread = get_thread($array[2]);
|
||||
$array[1] = $thread['fid'];
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
230
webroot/forum/inc/class_stopforumspamchecker.php
Normal file
230
webroot/forum/inc/class_stopforumspamchecker.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Registration checker to check registrations against the StopForumSpam.com database.
|
||||
*/
|
||||
class StopForumSpamChecker
|
||||
{
|
||||
/**
|
||||
* The base URL format to the stop forum spam API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const STOP_FORUM_SPAM_API_URL_FORMAT = 'http://api.stopforumspam.org/api?username=%s&email=%s&ip=%s&f=json&confidence';
|
||||
/**
|
||||
* @var pluginSystem
|
||||
*/
|
||||
private $plugins = null;
|
||||
/**
|
||||
* The minimum weighting before a user is considered to be a spammer.
|
||||
*
|
||||
* @var double
|
||||
*/
|
||||
private $min_weighting_before_spam = null;
|
||||
/**
|
||||
* Whether to check usernames against StopForumSPam. If set to false, the username weighting won't be used.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $check_usernames = false;
|
||||
/**
|
||||
* Whether to check email addresses against StopForumSPam. If set to false, the username weighting won't be used.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $check_emails = true;
|
||||
/**
|
||||
* Whether to check IP addresses against StopForumSPam. If set to false, the username weighting won't be used.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $check_ips = true;
|
||||
/**
|
||||
* Whether to log whenever a user is found to be a spammer.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $log_blocks;
|
||||
|
||||
/**
|
||||
* Create a new instance of the StopForumSpam.com checker.
|
||||
*
|
||||
* @param pluginSystem $plugins An instance of the plugin system.
|
||||
* @param double $min_weighting_before_spam The minimum confidence rating before a user is considered definitely spam.
|
||||
* @param bool $check_usernames Whether to check usernames against StopForumSpam.
|
||||
* @param bool $check_emails Whether to check email address against StopForumSpam.
|
||||
* @param bool $check_ips Whether to check IP addresses against StopForumSpam.
|
||||
*/
|
||||
public function __construct(&$plugins, $min_weighting_before_spam = 50.00, $check_usernames = false, $check_emails = true, $check_ips = true, $log_blocks = true)
|
||||
{
|
||||
$this->plugins = $plugins;
|
||||
$this->min_weighting_before_spam = (double)$min_weighting_before_spam;
|
||||
$this->check_usernames = (bool)$check_usernames;
|
||||
$this->check_emails = (bool)$check_emails;
|
||||
$this->check_ips = (bool)$check_ips;
|
||||
$this->log_blocks = (bool)$log_blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a user against the 3rd party service to determine whether they are a spammer.
|
||||
*
|
||||
* @param string $username The username of the user to check.
|
||||
* @param string $email The email address of the user to check.
|
||||
* @param string $ip_address The IP address sof the user to check.
|
||||
* @return bool Whether the user is considered a spammer or not.
|
||||
* @throws Exception Thrown when there's an error fetching from the StopForumSpam API or when the data cannot be decoded.
|
||||
*/
|
||||
public function is_user_a_spammer($username = '', $email = '', $ip_address = '')
|
||||
{
|
||||
$is_spammer = false;
|
||||
$checknum = $confidence = 0;
|
||||
|
||||
if(!filter_var($email, FILTER_VALIDATE_EMAIL))
|
||||
{
|
||||
throw new Exception("stopforumspam_invalid_email");
|
||||
}
|
||||
|
||||
if(!filter_var($ip_address, FILTER_VALIDATE_IP))
|
||||
{
|
||||
throw new Exception('stopforumspam_invalid_ip_address');
|
||||
}
|
||||
|
||||
$is_internal_ip = !filter_var(
|
||||
$ip_address,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||
);
|
||||
|
||||
if($is_internal_ip)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$username_encoded = urlencode($username);
|
||||
$email_encoded = urlencode($email);
|
||||
|
||||
$check_url = sprintf(self::STOP_FORUM_SPAM_API_URL_FORMAT, $username_encoded, $email_encoded, $ip_address);
|
||||
|
||||
$result = fetch_remote_file($check_url);
|
||||
|
||||
if($result !== false)
|
||||
{
|
||||
$result_json = @json_decode($result);
|
||||
|
||||
if($result_json != null && !isset($result_json->error))
|
||||
{
|
||||
if($this->check_usernames && $result_json->username->appears)
|
||||
{
|
||||
$checknum++;
|
||||
$confidence += $result_json->username->confidence;
|
||||
}
|
||||
|
||||
if($this->check_emails && $result_json->email->appears)
|
||||
{
|
||||
$checknum++;
|
||||
$confidence += $result_json->email->confidence;
|
||||
}
|
||||
|
||||
if($this->check_ips && $result_json->ip->appears)
|
||||
{
|
||||
$checknum++;
|
||||
$confidence += $result_json->ip->confidence;
|
||||
}
|
||||
|
||||
if($checknum > 0 && $confidence)
|
||||
{
|
||||
$confidence = $confidence / $checknum;
|
||||
}
|
||||
|
||||
if($confidence > $this->min_weighting_before_spam)
|
||||
{
|
||||
$is_spammer = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('stopforumspam_error_decoding');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('stopforumspam_error_retrieving');
|
||||
}
|
||||
|
||||
if($this->plugins)
|
||||
{
|
||||
$params = array(
|
||||
'username' => &$username,
|
||||
'email' => &$email,
|
||||
'ip_address' => &$ip_address,
|
||||
'is_spammer' => &$is_spammer,
|
||||
'confidence' => &$confidence,
|
||||
);
|
||||
|
||||
$this->plugins->run_hooks('stopforumspam_check_spammer_pre_return', $params);
|
||||
}
|
||||
|
||||
if($this->log_blocks && $is_spammer)
|
||||
{
|
||||
log_spam_block(
|
||||
$username, $email, $ip_address, array(
|
||||
'confidence' => (double)$confidence,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $is_spammer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $sfsSettingsEnabled
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getErrorText($sfsSettingsEnabled)
|
||||
{
|
||||
global $mybb, $lang;
|
||||
|
||||
foreach($sfsSettingsEnabled as $setting)
|
||||
{
|
||||
if($setting == 'stopforumspam_check_usernames' && $mybb->settings[$setting])
|
||||
{
|
||||
$settingsenabled[] = $lang->sfs_error_username;
|
||||
continue;
|
||||
}
|
||||
|
||||
if($setting == 'stopforumspam_check_emails' && $mybb->settings[$setting])
|
||||
{
|
||||
$settingsenabled[] = $lang->sfs_error_email;
|
||||
continue;
|
||||
}
|
||||
|
||||
if($setting = 'stopforumspam_check_ips' && $mybb->settings[$setting])
|
||||
{
|
||||
$settingsenabled[] = $lang->sfs_error_ip;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(sizeof($settingsenabled) > 1)
|
||||
{
|
||||
$lastsetting = $settingsenabled[sizeof($settingsenabled)-1];
|
||||
unset($settingsenabled[sizeof($settingsenabled)-1]);
|
||||
|
||||
$stopforumspamerror = implode($lang->comma, $settingsenabled) . " {$lang->sfs_error_or} " . $lastsetting;
|
||||
}
|
||||
else
|
||||
{
|
||||
$stopforumspamerror = $settingsenabled[0];
|
||||
}
|
||||
return $stopforumspamerror;
|
||||
}
|
||||
}
|
||||
163
webroot/forum/inc/class_templates.php
Normal file
163
webroot/forum/inc/class_templates.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
class templates
|
||||
{
|
||||
/**
|
||||
* The total number of templates.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $total = 0;
|
||||
|
||||
/**
|
||||
* The template cache.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $cache = array();
|
||||
|
||||
/**
|
||||
* Array of templates loaded that were not loaded via the cache
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $uncached_templates = array();
|
||||
|
||||
/**
|
||||
* Cache the templates.
|
||||
*
|
||||
* @param string $templates A list of templates to cache.
|
||||
*/
|
||||
function cache($templates)
|
||||
{
|
||||
global $db, $theme;
|
||||
$sql = $sqladd = "";
|
||||
$names = explode(",", $templates);
|
||||
foreach($names as $key => $title)
|
||||
{
|
||||
$sql .= " ,'".trim($title)."'";
|
||||
}
|
||||
|
||||
$query = $db->simple_select("templates", "title,template", "title IN (''$sql) AND sid IN ('-2','-1','".$theme['templateset']."')", array('order_by' => 'sid', 'order_dir' => 'asc'));
|
||||
while($template = $db->fetch_array($query))
|
||||
{
|
||||
$this->cache[$template['title']] = $template['template'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets templates.
|
||||
*
|
||||
* @param string $title The title of the template to get.
|
||||
* @param boolean|int $eslashes True if template contents must be escaped, false if not.
|
||||
* @param boolean|int $htmlcomments True to output HTML comments, false to not output.
|
||||
* @return string The template HTML.
|
||||
*/
|
||||
function get($title, $eslashes=1, $htmlcomments=1)
|
||||
{
|
||||
global $db, $theme, $mybb;
|
||||
|
||||
//
|
||||
// DEVELOPMENT MODE
|
||||
//
|
||||
if($mybb->dev_mode == 1)
|
||||
{
|
||||
$template = $this->dev_get($title);
|
||||
if($template !== false)
|
||||
{
|
||||
$this->cache[$title] = $template;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($this->cache[$title]))
|
||||
{
|
||||
// Only load master and global templates if template is needed in Admin CP
|
||||
if(empty($theme['templateset']))
|
||||
{
|
||||
$query = $db->simple_select("templates", "template", "title='".$db->escape_string($title)."' AND sid IN ('-2','-1')", array('order_by' => 'sid', 'order_dir' => 'DESC', 'limit' => 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
$query = $db->simple_select("templates", "template", "title='".$db->escape_string($title)."' AND sid IN ('-2','-1','".$theme['templateset']."')", array('order_by' => 'sid', 'order_dir' => 'DESC', 'limit' => 1));
|
||||
}
|
||||
|
||||
$gettemplate = $db->fetch_array($query);
|
||||
if($mybb->debug_mode)
|
||||
{
|
||||
$this->uncached_templates[$title] = $title;
|
||||
}
|
||||
|
||||
if(!$gettemplate)
|
||||
{
|
||||
$gettemplate['template'] = "";
|
||||
}
|
||||
|
||||
$this->cache[$title] = $gettemplate['template'];
|
||||
}
|
||||
$template = $this->cache[$title];
|
||||
|
||||
if($htmlcomments)
|
||||
{
|
||||
if($mybb->settings['tplhtmlcomments'] == 1)
|
||||
{
|
||||
$template = "<!-- start: ".htmlspecialchars_uni($title)." -->\n{$template}\n<!-- end: ".htmlspecialchars_uni($title)." -->";
|
||||
}
|
||||
else
|
||||
{
|
||||
$template = "\n{$template}\n";
|
||||
}
|
||||
}
|
||||
|
||||
if($eslashes)
|
||||
{
|
||||
$template = str_replace("\\'", "'", addslashes($template));
|
||||
}
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a template for rendering to a variable.
|
||||
*
|
||||
* @param string $template The name of the template to get.
|
||||
* @param boolean $eslashes True if template contents must be escaped, false if not.
|
||||
* @param boolean $htmlcomments True to output HTML comments, false to not output.
|
||||
* @return string The eval()-ready PHP code for rendering the template
|
||||
*/
|
||||
function render($template, $eslashes=true, $htmlcomments=true)
|
||||
{
|
||||
return 'return "'.$this->get($template, $eslashes, $htmlcomments).'";';
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a template directly from the install/resources/mybb_theme.xml directory if it exists (DEVELOPMENT MODE)
|
||||
*
|
||||
* @param string $title
|
||||
* @return string|bool
|
||||
*/
|
||||
function dev_get($title)
|
||||
{
|
||||
static $template_xml;
|
||||
|
||||
if(!$template_xml)
|
||||
{
|
||||
if(@file_exists(MYBB_ROOT."install/resources/mybb_theme.xml"))
|
||||
{
|
||||
$template_xml = simplexml_load_file(MYBB_ROOT."install/resources/mybb_theme.xml");
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$res = $template_xml->xpath("//template[@name='{$title}']");
|
||||
return $res[0];
|
||||
}
|
||||
}
|
||||
133
webroot/forum/inc/class_timers.php
Normal file
133
webroot/forum/inc/class_timers.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
class timer {
|
||||
|
||||
/**
|
||||
* The timer name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* The start time of this timer.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $start;
|
||||
|
||||
/**
|
||||
* The end time of this timer.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $end;
|
||||
|
||||
/**
|
||||
* The total time this timer has run.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $totaltime;
|
||||
|
||||
/**
|
||||
* The formatted total time this timer has run.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $formatted;
|
||||
|
||||
/**
|
||||
* Constructor of class.
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
$this->add();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timer.
|
||||
*
|
||||
*/
|
||||
function add()
|
||||
{
|
||||
if(!$this->start)
|
||||
{
|
||||
$this->start = microtime(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time for which the timer has run up until this point.
|
||||
*
|
||||
* @return string|boolean The formatted time up until now or false when timer is no longer running.
|
||||
*/
|
||||
function getTime()
|
||||
{
|
||||
if($this->end) // timer has been stopped
|
||||
{
|
||||
return $this->totaltime;
|
||||
}
|
||||
elseif($this->start && !$this->end) // timer is still going
|
||||
{
|
||||
$currenttime = microtime(true);
|
||||
$totaltime = $currenttime - $this->start;
|
||||
return $this->format($totaltime);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the timer.
|
||||
*
|
||||
* @return string The formatted total time.
|
||||
*/
|
||||
function stop()
|
||||
{
|
||||
if($this->start)
|
||||
{
|
||||
$this->end = microtime(true);
|
||||
$totaltime = $this->end - $this->start;
|
||||
$this->totaltime = $totaltime;
|
||||
$this->formatted = $this->format($totaltime);
|
||||
return $this->formatted;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the timer.
|
||||
*
|
||||
*/
|
||||
function remove()
|
||||
{
|
||||
$this->name = "";
|
||||
$this->start = "";
|
||||
$this->end = "";
|
||||
$this->totaltime = "";
|
||||
$this->formatted = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the timer time in a pretty way.
|
||||
*
|
||||
* @param string $string The time string.
|
||||
* @return string The formatted time string.
|
||||
*/
|
||||
function format($string)
|
||||
{
|
||||
return number_format($string, 7);
|
||||
}
|
||||
}
|
||||
182
webroot/forum/inc/class_xml.php
Normal file
182
webroot/forum/inc/class_xml.php
Normal file
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The following class is based upon code by Eric Pollman
|
||||
* @ http://eric.pollman.net/work/public_domain/
|
||||
* and is licensed under the public domain license.
|
||||
*/
|
||||
|
||||
class XMLParser {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $data;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $vals;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $collapse_dups = 1;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $index_numeric = 0;
|
||||
|
||||
/**
|
||||
* Initialize the parser and store the XML data to be parsed.
|
||||
*
|
||||
* @param string $data
|
||||
*/
|
||||
function __construct($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a tree based structure based from the parsed data
|
||||
*
|
||||
* @return array The tree based structure
|
||||
*/
|
||||
function get_tree()
|
||||
{
|
||||
$parser = xml_parser_create();
|
||||
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
|
||||
xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
|
||||
if(!xml_parse_into_struct($parser, $this->data, $vals, $index))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$i = -1;
|
||||
return $this->get_children($vals, $i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private: Build a completed tag by fetching all child nodes and attributes
|
||||
*
|
||||
* @param array $thisvals Array of values from the current tag
|
||||
* @param array $vals Array of child nodes
|
||||
* @param int $i Internal counter
|
||||
* @param string $type Type of tag. Complete is a single line tag with attributes
|
||||
* @return array Completed tag array
|
||||
*/
|
||||
function build_tag($thisvals, $vals, &$i, $type)
|
||||
{
|
||||
$tag = array('tag' => $thisvals['tag']);
|
||||
|
||||
if(isset($thisvals['attributes']))
|
||||
{
|
||||
$tag['attributes'] = $thisvals['attributes'];
|
||||
}
|
||||
|
||||
if($type == "complete")
|
||||
{
|
||||
if(isset($thisvals['value']))
|
||||
{
|
||||
$tag['value'] = $thisvals['value'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$tag = array_merge($tag, $this->get_children($vals, $i));
|
||||
}
|
||||
return $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the children for from a specific node array
|
||||
*
|
||||
* @param array $vals Array of children
|
||||
* @param int $i Internal counter
|
||||
* @return array Array of child nodes
|
||||
*/
|
||||
function get_children($vals=array(), &$i)
|
||||
{
|
||||
$children = array();
|
||||
|
||||
if($i > -1 && isset($vals[$i]['value']))
|
||||
{
|
||||
$children['value'] = $vals[$i]['value'];
|
||||
}
|
||||
|
||||
while(++$i < count($vals))
|
||||
{
|
||||
$type = $vals[$i]['type'];
|
||||
if($type == "cdata")
|
||||
{
|
||||
$children['value'] .= $vals[$i]['value'];
|
||||
}
|
||||
elseif($type == "complete" || $type == "open")
|
||||
{
|
||||
$tag = $this->build_tag($vals[$i], $vals, $i, $type);
|
||||
if($this->index_numeric)
|
||||
{
|
||||
$tag['tag'] = $vals[$i]['tag'];
|
||||
$children[] = $tag;
|
||||
}
|
||||
else
|
||||
{
|
||||
$children[$tag['tag']][] = $tag;
|
||||
}
|
||||
}
|
||||
else if($type == "close")
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if($this->collapse_dups)
|
||||
{
|
||||
foreach($children as $key => $value)
|
||||
{
|
||||
if(is_array($value) && (count($value) == 1))
|
||||
{
|
||||
$children[$key] = $value[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $children;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill off unnecessary tags and return a clean array of XML data
|
||||
*
|
||||
* @param array $array Array of parsed XML data
|
||||
* @return array Cleaned array of XML data
|
||||
*/
|
||||
function kill_tags($array)
|
||||
{
|
||||
foreach($array as $key => $val)
|
||||
{
|
||||
if($key == "tag" || $key == "value")
|
||||
{
|
||||
unset($array[$key]);
|
||||
}
|
||||
else if(is_array($val))
|
||||
{
|
||||
// kill any nested tag or value indexes
|
||||
$array[$key] = kill_tags($val);
|
||||
|
||||
// if the array no longer has any key/val sets
|
||||
// and therefore is at the deepest level, then
|
||||
// store the string value
|
||||
if(is_array($array[$key]) && count($array[$key]) <= 0)
|
||||
{
|
||||
$array[$key] = $val['value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
217
webroot/forum/inc/datahandler.php
Normal file
217
webroot/forum/inc/datahandler.php
Normal file
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base data handler class.
|
||||
*
|
||||
*/
|
||||
class DataHandler
|
||||
{
|
||||
/**
|
||||
* The data being managed by the data handler
|
||||
*
|
||||
* @var array Data being handled by the data handler.
|
||||
*/
|
||||
public $data = array();
|
||||
|
||||
/**
|
||||
* Whether or not the data has been validated. Note: "validated" != "valid".
|
||||
*
|
||||
* @var boolean True when validated, false when not validated.
|
||||
*/
|
||||
public $is_validated = false;
|
||||
|
||||
/**
|
||||
* The errors that occurred when handling data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* The status of administrator override powers.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $admin_override = false;
|
||||
|
||||
/**
|
||||
* Defines if we're performing an update or an insert.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $method;
|
||||
|
||||
/**
|
||||
* The prefix for the language variables used in the data handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language_prefix = '';
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for the data handler.
|
||||
*
|
||||
* @param string $method The method we're performing with this object.
|
||||
*/
|
||||
function __construct($method="insert")
|
||||
{
|
||||
if($method != "update" && $method != "insert" && $method != "get" && $method != "delete")
|
||||
{
|
||||
die("A valid method was not supplied to the data handler.");
|
||||
}
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data to be used for the data handler
|
||||
*
|
||||
* @param array $data The data.
|
||||
* @return bool
|
||||
*/
|
||||
function set_data($data)
|
||||
{
|
||||
if(!is_array($data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$this->data = $data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error to the error array.
|
||||
*
|
||||
* @param string $error The error name.
|
||||
* @param string $data
|
||||
*/
|
||||
function set_error($error, $data='')
|
||||
{
|
||||
$this->errors[$error] = array(
|
||||
"error_code" => $error,
|
||||
"data" => $data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error(s) that occurred when handling data.
|
||||
*
|
||||
* @return array An array of errors.
|
||||
*/
|
||||
function get_errors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error(s) that occurred when handling data
|
||||
* in a format that MyBB can handle.
|
||||
*
|
||||
* @return array An array of errors in a MyBB format.
|
||||
*/
|
||||
function get_friendly_errors()
|
||||
{
|
||||
global $lang;
|
||||
|
||||
// Load the language pack we need
|
||||
if($this->language_file)
|
||||
{
|
||||
$lang->load($this->language_file, true);
|
||||
}
|
||||
// Prefix all the error codes with the language prefix.
|
||||
$errors = array();
|
||||
foreach($this->errors as $error)
|
||||
{
|
||||
$lang_string = $this->language_prefix.'_'.$error['error_code'];
|
||||
if(!$lang->$lang_string)
|
||||
{
|
||||
$errors[] = $error['error_code'];
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!empty($error['data']) && !is_array($error['data']))
|
||||
{
|
||||
$error['data'] = array($error['data']);
|
||||
}
|
||||
|
||||
if(is_array($error['data']))
|
||||
{
|
||||
array_unshift($error['data'], $lang->$lang_string);
|
||||
$errors[] = call_user_func_array(array($lang, "sprintf"), $error['data']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$errors[] = $lang->$lang_string;
|
||||
}
|
||||
}
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not we are done validating.
|
||||
*
|
||||
* @param boolean True when done, false when not done.
|
||||
*/
|
||||
function set_validated($validated = true)
|
||||
{
|
||||
$this->is_validated = $validated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not we are done validating.
|
||||
*
|
||||
* @return boolean True when done, false when not done.
|
||||
*/
|
||||
function get_validated()
|
||||
{
|
||||
if($this->is_validated == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if yes/no options haven't been modified.
|
||||
*
|
||||
* @param array $options The user options array.
|
||||
* @param string $option The specific option to check.
|
||||
* @param int|bool $default Optionally specify if the default should be used.
|
||||
*/
|
||||
function verify_yesno_option(&$options, $option, $default=1)
|
||||
{
|
||||
if($this->method == "insert" || array_key_exists($option, $options))
|
||||
{
|
||||
if(isset($options[$option]) && $options[$option] != $default && $options[$option] != "")
|
||||
{
|
||||
if($default == 1)
|
||||
{
|
||||
$options[$option] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$options[$option] = 1;
|
||||
}
|
||||
}
|
||||
else if(@array_key_exists($option, $options) && $options[$option] == '')
|
||||
{
|
||||
$options[$option] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$options[$option] = $default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
643
webroot/forum/inc/datahandlers/event.php
Normal file
643
webroot/forum/inc/datahandlers/event.php
Normal file
@@ -0,0 +1,643 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handling class, provides common structure to handle event data.
|
||||
*
|
||||
*/
|
||||
class EventDataHandler extends DataHandler
|
||||
{
|
||||
/**
|
||||
* The language file used in the data handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language_file = 'datahandler_event';
|
||||
|
||||
/**
|
||||
* The prefix for the language variables used in the data handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language_prefix = 'eventdata';
|
||||
|
||||
/**
|
||||
* Array of data inserted in to an event.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $event_insert_data = array();
|
||||
|
||||
/**
|
||||
* Array of data used to update an event.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $event_update_data = array();
|
||||
|
||||
/**
|
||||
* Event ID currently being manipulated by the datahandlers.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $eid = 0;
|
||||
|
||||
/**
|
||||
* Values to be returned after inserting/updating an event.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $return_values = array();
|
||||
|
||||
/**
|
||||
* Verifies if an event name is valid or not and attempts to fix it
|
||||
*
|
||||
* @return boolean True if valid, false if invalid.
|
||||
*/
|
||||
function verify_name()
|
||||
{
|
||||
$name = &$this->data['name'];
|
||||
$name = trim($name);
|
||||
if(!$name)
|
||||
{
|
||||
$this->set_error("missing_name");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if an event description is valid or not and attempts to fix it
|
||||
*
|
||||
* @return boolean True if valid, false if invalid.
|
||||
*/
|
||||
function verify_description()
|
||||
{
|
||||
$description = &$this->data['description'];
|
||||
$description = trim($description);
|
||||
if(!$description)
|
||||
{
|
||||
$this->set_error("missing_description");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if an event date is valid or not and attempts to fix it
|
||||
*
|
||||
* @return boolean True if valid, false if invalid.
|
||||
*/
|
||||
function verify_date()
|
||||
{
|
||||
$event = &$this->data;
|
||||
|
||||
// All types of events require a start date
|
||||
if(!$event['start_date']['day'] || !$event['start_date']['month'] || !$event['start_date']['year'])
|
||||
{
|
||||
$this->set_error("invalid_start_date");
|
||||
return false;
|
||||
}
|
||||
|
||||
$event['start_date']['day'] = (int)$event['start_date']['day'];
|
||||
$event['start_date']['month'] = (int)$event['start_date']['month'];
|
||||
$event['start_date']['year'] = (int)$event['start_date']['year'];
|
||||
|
||||
if($event['start_date']['day'] > date("t", mktime(0, 0, 0, $event['start_date']['month'], 1, $event['start_date']['year'])))
|
||||
{
|
||||
$this->set_error("invalid_start_date");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calendar events can only be within the next 5 years
|
||||
if($event['start_date']['year'] > date("Y") + 5)
|
||||
{
|
||||
$this->set_error("invalid_start_year");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check to see if the month is within 1 and 12
|
||||
if($event['start_date']['month'] > 12 || $event['start_date']['month'] < 1)
|
||||
{
|
||||
$this->set_error("invalid_start_month");
|
||||
return false;
|
||||
}
|
||||
|
||||
// For ranged events, we check the end date & times too
|
||||
if($event['type'] == "ranged")
|
||||
{
|
||||
if(!$event['end_date']['day'] || !$event['end_date']['month'] || !$event['end_date']['year'])
|
||||
{
|
||||
$this->set_error("invalid_end_date");
|
||||
return false;
|
||||
}
|
||||
|
||||
$event['end_date']['day'] = (int)$event['end_date']['day'];
|
||||
$event['end_date']['month'] = (int)$event['end_date']['month'];
|
||||
$event['end_date']['year'] = (int)$event['end_date']['year'];
|
||||
|
||||
if($event['end_date']['day'] > date("t", mktime(0, 0, 0, $event['end_date']['month'], 1, $event['end_date']['year'])))
|
||||
{
|
||||
$this->set_error("invalid_end_date");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calendar events can only be within the next 5 years
|
||||
if($event['end_date']['year'] > date("Y") + 5)
|
||||
{
|
||||
$this->set_error("invalid_end_year");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check to see if the month is within 1 and 12
|
||||
if($event['end_date']['month'] > 12 || $event['end_date']['month'] < 1)
|
||||
{
|
||||
$this->set_error("invalid_end_month");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate time input
|
||||
if($event['start_date']['time'] || $event['end_date']['time'])
|
||||
{
|
||||
if(($event['start_date']['time'] && !$event['end_date']['time']) || ($event['end_date']['time'] && !$event['start_date']['time']))
|
||||
{
|
||||
$this->set_error("cant_specify_one_time");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Begin start time validation
|
||||
$start_time = $this->verify_time($event['start_date']['time']);
|
||||
if(!is_array($start_time))
|
||||
{
|
||||
$this->set_error("start_time_invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
// End time validation
|
||||
$end_time = $this->verify_time($event['end_date']['time']);
|
||||
if(!is_array($end_time))
|
||||
{
|
||||
$this->set_error("end_time_invalid");
|
||||
return false;
|
||||
}
|
||||
$event['usingtime'] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$start_time = array("hour" => 0, "min" => 0);
|
||||
$end_time = array("hour" => 23, "min" => 59);
|
||||
$event['usingtime'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists('timezone', $event))
|
||||
{
|
||||
$event['timezone'] = (float)$event['timezone'];
|
||||
if($event['timezone'] > 12 || $event['timezone'] < -12)
|
||||
{
|
||||
$this->set_error("invalid_timezone");
|
||||
return false;
|
||||
}
|
||||
$start_time['hour'] -= $event['timezone'];
|
||||
$end_time['hour'] -= $event['timezone'];
|
||||
}
|
||||
|
||||
if(!isset($start_time))
|
||||
{
|
||||
$start_time = array("hour" => 0, "min" => 0);
|
||||
}
|
||||
|
||||
$start_timestamp = gmmktime($start_time['hour'], $start_time['min'], 0, $event['start_date']['month'], $event['start_date']['day'], $event['start_date']['year']);
|
||||
|
||||
if($event['type'] == "ranged")
|
||||
{
|
||||
$end_timestamp = gmmktime($end_time['hour'], $end_time['min'], 0, $event['end_date']['month'], $event['end_date']['day'], $event['end_date']['year']);
|
||||
|
||||
if($end_timestamp <= $start_timestamp)
|
||||
{
|
||||
$this->set_error("end_in_past");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($end_timestamp))
|
||||
{
|
||||
$end_timestamp = 0;
|
||||
}
|
||||
|
||||
// Save our time stamps for saving
|
||||
$event['starttime'] = $start_timestamp;
|
||||
$event['endtime'] = $end_timestamp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $time
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
function verify_time($time)
|
||||
{
|
||||
preg_match('#^(0?[1-9]|1[012])\s?([:\.]?)\s?([0-5][0-9])?(\s?[ap]m)|([01][0-9]|2[0-3])\s?([:\.])\s?([0-5][0-9])$#i', $time, $matches);
|
||||
if(count($matches) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 24h time
|
||||
if(count($matches) == 8)
|
||||
{
|
||||
$hour = $matches[5];
|
||||
$min = $matches[7];
|
||||
}
|
||||
// 12 hour time
|
||||
else
|
||||
{
|
||||
$hour = $matches[1];
|
||||
$min = (int)$matches[3];
|
||||
$matches[4] = trim($matches[4]);
|
||||
if(my_strtolower($matches[4]) == "pm" && $hour != 12)
|
||||
{
|
||||
$hour += 12;
|
||||
}
|
||||
else if(my_strtolower($matches[4]) == "am" && $hour == 12)
|
||||
{
|
||||
$hour = 0;
|
||||
}
|
||||
}
|
||||
return array("hour" => $hour, "min" => $min);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function verify_repeats()
|
||||
{
|
||||
$event = &$this->data;
|
||||
|
||||
if(!is_array($event['repeats']) || !$event['repeats']['repeats'])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!$event['endtime'])
|
||||
{
|
||||
$this->set_error("only_ranged_events_repeat");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($event['repeats']['repeats'])
|
||||
{
|
||||
case 1:
|
||||
$event['repeats']['days'] = (int)$event['repeats']['days'];
|
||||
if($event['repeats']['days'] <= 0)
|
||||
{
|
||||
$this->set_error("invalid_repeat_day_interval");
|
||||
return false;
|
||||
}
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
$event['repeats']['weeks'] = (int)$event['repeats']['weeks'];
|
||||
if($event['repeats']['weeks'] <= 0)
|
||||
{
|
||||
$this->set_error("invalid_repeat_week_interval");
|
||||
return false;
|
||||
}
|
||||
if(is_array($event['repeats']['days']) && count($event['repeats']['days']) == 0)
|
||||
{
|
||||
$this->set_error("invalid_repeat_weekly_days");
|
||||
return false;
|
||||
}
|
||||
asort($event['repeats']['days']);
|
||||
break;
|
||||
case 4:
|
||||
if($event['repeats']['day'])
|
||||
{
|
||||
$event['repeats']['day'] = (int)$event['repeats']['day'];
|
||||
if($event['repeats']['day'] <= 0 || $event['repeats']['day'] > 31)
|
||||
{
|
||||
$this->set_error("invalid_repeat_day_interval");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($event['repeats']['occurance'] != "last")
|
||||
{
|
||||
$event['repeats']['occurance'] = (int)$event['repeats']['occurance'];
|
||||
}
|
||||
$event['repeats']['weekday'] = (int)$event['repeats']['weekday'];
|
||||
}
|
||||
$event['repeats']['months'] = (int)$event['repeats']['months'];
|
||||
if($event['repeats']['months'] <= 0 || $event['repeats']['months'] > 12)
|
||||
{
|
||||
$this->set_error("invalid_repeat_month_interval");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if($event['repeats']['day'])
|
||||
{
|
||||
$event['repeats']['day'] = (int)$event['repeats']['day'];
|
||||
if($event['repeats']['day'] <= 0 || $event['repeats']['day'] > 31)
|
||||
{
|
||||
$this->set_error("invalid_repeat_day_interval");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($event['repeats']['occurance'] != "last")
|
||||
{
|
||||
$event['repeats']['occurance'] = (int)$event['repeats']['occurance'];
|
||||
}
|
||||
$event['repeats']['weekday'] = (int)$event['repeats']['weekday'];
|
||||
}
|
||||
$event['repeats']['month'] = (int)$event['repeats']['month'];
|
||||
if($event['repeats']['month'] <= 0 || $event['repeats']['month'] > 12)
|
||||
{
|
||||
$this->set_error("invalid_repeat_month_interval");
|
||||
return false;
|
||||
}
|
||||
$event['repeats']['years'] = (int)$event['repeats']['years'];
|
||||
if($event['repeats']['years'] <= 0 || $event['repeats']['years'] > 4)
|
||||
{
|
||||
$this->set_error("invalid_repeat_year_interval");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$event['repeats'] = array();
|
||||
}
|
||||
require_once MYBB_ROOT."inc/functions_calendar.php";
|
||||
$event['starttime_user'] = $event['starttime'];
|
||||
$event['endtime_user'] = $event['endtime'];
|
||||
$next_occurance = fetch_next_occurance($event, array('start' => $event['starttime'], 'end' => $event['endtime']), $event['starttime'], true);
|
||||
if($next_occurance > $event['endtime'])
|
||||
{
|
||||
$this->set_error("event_wont_occur");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an event.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function validate_event()
|
||||
{
|
||||
global $plugins;
|
||||
|
||||
$event = &$this->data;
|
||||
|
||||
if($this->method == "insert" || array_key_exists('name', $event))
|
||||
{
|
||||
$this->verify_name();
|
||||
}
|
||||
|
||||
if($this->method == "insert" || array_key_exists('description', $event))
|
||||
{
|
||||
$this->verify_description();
|
||||
}
|
||||
|
||||
if($this->method == "insert" || array_key_exists('start_date', $event) || array_key_exists('end_date', $event))
|
||||
{
|
||||
$this->verify_date();
|
||||
}
|
||||
|
||||
if(($this->method == "insert" && $event['endtime']) || array_key_exists('repeats', $event))
|
||||
{
|
||||
$this->verify_repeats();
|
||||
}
|
||||
|
||||
$plugins->run_hooks("datahandler_event_validate", $this);
|
||||
|
||||
// We are done validating, return.
|
||||
$this->set_validated(true);
|
||||
if(count($this->get_errors()) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an event into the database.
|
||||
*
|
||||
* @return array Array of new event details, eid and private.
|
||||
*/
|
||||
function insert_event()
|
||||
{
|
||||
global $db, $mybb, $plugins;
|
||||
|
||||
// Yes, validating is required.
|
||||
if(!$this->get_validated())
|
||||
{
|
||||
die("The event needs to be validated before inserting it into the DB.");
|
||||
}
|
||||
|
||||
if(count($this->get_errors()) > 0)
|
||||
{
|
||||
die("The event is not valid.");
|
||||
}
|
||||
|
||||
$event = &$this->data;
|
||||
|
||||
$query = $db->simple_select("calendars", "*", "cid='".(int)$event['cid']."'");
|
||||
$calendar_moderation = $db->fetch_field($query, "moderation");
|
||||
if($calendar_moderation == 1 && (int)$event['private'] != 1)
|
||||
{
|
||||
$visible = 0;
|
||||
if($event['uid'] == $mybb->user['uid'])
|
||||
{
|
||||
$calendar_permissions = get_calendar_permissions($event['cid']);
|
||||
if($calendar_permissions['canbypasseventmod'] == 1)
|
||||
{
|
||||
$visible = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$visible = 1;
|
||||
}
|
||||
|
||||
// Prepare an array for insertion into the database.
|
||||
$this->event_insert_data = array(
|
||||
'cid' => (int)$event['cid'],
|
||||
'uid' => (int)$event['uid'],
|
||||
'name' => $db->escape_string($event['name']),
|
||||
'description' => $db->escape_string($event['description']),
|
||||
'visible' => $visible,
|
||||
'private' => (int)$event['private'],
|
||||
'dateline' => TIME_NOW,
|
||||
'starttime' => (int)$event['starttime'],
|
||||
'endtime' => (int)$event['endtime']
|
||||
);
|
||||
|
||||
if(isset($event['timezone']))
|
||||
{
|
||||
$this->event_insert_data['timezone'] = $db->escape_string((float)$event['timezone']);
|
||||
}
|
||||
|
||||
if(isset($event['ignoretimezone']))
|
||||
{
|
||||
$this->event_insert_data['ignoretimezone'] = (int)$event['ignoretimezone'];
|
||||
}
|
||||
|
||||
if(isset($event['usingtime']))
|
||||
{
|
||||
$this->event_insert_data['usingtime'] = (int)$event['usingtime'];
|
||||
}
|
||||
|
||||
if(isset($event['repeats']))
|
||||
{
|
||||
$this->event_insert_data['repeats'] = $db->escape_string(my_serialize($event['repeats']));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->event_insert_data['repeats'] = '';
|
||||
}
|
||||
|
||||
$plugins->run_hooks("datahandler_event_insert", $this);
|
||||
|
||||
$this->eid = $db->insert_query("events", $this->event_insert_data);
|
||||
|
||||
// Return the event's eid and whether or not it is private.
|
||||
$this->return_values = array(
|
||||
'eid' => $this->eid,
|
||||
'private' => $event['private'],
|
||||
'visible' => $visible
|
||||
);
|
||||
|
||||
$plugins->run_hooks("datahandler_event_insert_end", $this);
|
||||
|
||||
return $this->return_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an event that is already in the database.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function update_event()
|
||||
{
|
||||
global $db, $plugins;
|
||||
|
||||
// Yes, validating is required.
|
||||
if(!$this->get_validated())
|
||||
{
|
||||
die("The event needs to be validated before inserting it into the DB.");
|
||||
}
|
||||
|
||||
if(count($this->get_errors()) > 0)
|
||||
{
|
||||
die("The event is not valid.");
|
||||
}
|
||||
|
||||
$event = &$this->data;
|
||||
|
||||
$this->eid = $event['eid'];
|
||||
|
||||
if(isset($event['cid']))
|
||||
{
|
||||
$this->event_update_data['cid'] = $db->escape_string($event['cid']);
|
||||
}
|
||||
|
||||
if(isset($event['name']))
|
||||
{
|
||||
$this->event_update_data['name'] = $db->escape_string($event['name']);
|
||||
}
|
||||
|
||||
if(isset($event['description']))
|
||||
{
|
||||
$this->event_update_data['description'] = $db->escape_string($event['description']);
|
||||
}
|
||||
|
||||
if(isset($event['starttime']))
|
||||
{
|
||||
$this->event_update_data['starttime'] = (int)$event['starttime'];
|
||||
$this->event_update_data['usingtime'] = (int)$event['usingtime'];
|
||||
}
|
||||
|
||||
if(isset($event['endtime']))
|
||||
{
|
||||
$this->event_update_data['endtime'] = (int)$event['endtime'];
|
||||
$this->event_update_data['usingtime'] = (int)$event['usingtime'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->event_update_data['endtime'] = 0;
|
||||
$this->event_update_data['usingtime'] = 0;
|
||||
}
|
||||
|
||||
if(isset($event['repeats']))
|
||||
{
|
||||
if(!empty($event['repeats']))
|
||||
{
|
||||
$event['repeats'] = my_serialize($event['repeats']);
|
||||
}
|
||||
$this->event_update_data['repeats'] = $db->escape_string($event['repeats']);
|
||||
}
|
||||
|
||||
if(isset($event['timezone']))
|
||||
{
|
||||
$this->event_update_data['timezone'] = $db->escape_string((float)$event['timezone']);
|
||||
}
|
||||
|
||||
if(isset($event['ignoretimezone']))
|
||||
{
|
||||
$this->event_update_data['ignoretimezone'] = (int)$event['ignoretimezone'];
|
||||
}
|
||||
|
||||
if(isset($event['private']))
|
||||
{
|
||||
$this->event_update_data['private'] = (int)$event['private'];
|
||||
}
|
||||
|
||||
if(isset($event['visible']))
|
||||
{
|
||||
$this->event_update_data['visible'] = $db->escape_string($event['visible']);
|
||||
}
|
||||
|
||||
if(isset($event['uid']))
|
||||
{
|
||||
$this->event_update_data['uid'] = (int)$event['uid'];
|
||||
}
|
||||
|
||||
$plugins->run_hooks("datahandler_event_update", $this);
|
||||
|
||||
$db->update_query("events", $this->event_update_data, "eid='".(int)$event['eid']."'");
|
||||
|
||||
// Return the event's eid and whether or not it is private.
|
||||
$this->return_values = array(
|
||||
'eid' => $event['eid'],
|
||||
'private' => $event['private']
|
||||
);
|
||||
|
||||
$plugins->run_hooks("datahandler_event_update_end", $this);
|
||||
|
||||
return $this->return_values;
|
||||
}
|
||||
}
|
||||
|
||||
8
webroot/forum/inc/datahandlers/index.html
Normal file
8
webroot/forum/inc/datahandlers/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
340
webroot/forum/inc/datahandlers/login.php
Normal file
340
webroot/forum/inc/datahandlers/login.php
Normal file
@@ -0,0 +1,340 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Login handling class, provides common structure to handle login events.
|
||||
*
|
||||
*/
|
||||
class LoginDataHandler extends DataHandler
|
||||
{
|
||||
/**
|
||||
* The language file used in the data handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language_file = 'datahandler_login';
|
||||
|
||||
/**
|
||||
* The prefix for the language variables used in the data handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language_prefix = 'logindata';
|
||||
|
||||
/**
|
||||
* Array of data used via login events.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $login_data = array();
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $captcha_verified = true;
|
||||
|
||||
/**
|
||||
* @var bool|captcha
|
||||
*/
|
||||
private $captcha = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $username_method = null;
|
||||
|
||||
/**
|
||||
* @param int $check_captcha
|
||||
*/
|
||||
function verify_attempts($check_captcha = 0)
|
||||
{
|
||||
global $db, $mybb;
|
||||
|
||||
$user = &$this->data;
|
||||
|
||||
if($check_captcha)
|
||||
{
|
||||
if(!isset($mybb->cookies['loginattempts']))
|
||||
{
|
||||
$mybb->cookies['loginattempts'] = 0;
|
||||
}
|
||||
if($mybb->settings['failedcaptchalogincount'] > 0 && ($user['loginattempts'] > $mybb->settings['failedcaptchalogincount'] || (int)$mybb->cookies['loginattempts'] > $mybb->settings['failedcaptchalogincount']))
|
||||
{
|
||||
$this->captcha_verified = false;
|
||||
$this->verify_captcha();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function verify_captcha()
|
||||
{
|
||||
global $db, $mybb;
|
||||
|
||||
$user = &$this->data;
|
||||
|
||||
if($user['imagestring'] || $mybb->settings['captchaimage'] != 1)
|
||||
{
|
||||
// Check their current captcha input - if correct, hide the captcha input area
|
||||
require_once MYBB_ROOT.'inc/class_captcha.php';
|
||||
$this->captcha = new captcha;
|
||||
|
||||
if($this->captcha->validate_captcha() == false)
|
||||
{
|
||||
// CAPTCHA validation failed
|
||||
foreach($this->captcha->get_errors() as $error)
|
||||
{
|
||||
$this->set_error($error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->captcha_verified = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if($mybb->input['quick_login'] == 1 && $mybb->input['quick_password'] && $mybb->input['quick_username'])
|
||||
{
|
||||
$this->set_error('regimagerequired');
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->set_error('regimageinvalid');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function verify_username()
|
||||
{
|
||||
$this->get_login_data();
|
||||
|
||||
if(!$this->login_data['uid'])
|
||||
{
|
||||
$this->invalid_combination();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $strict
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function verify_password($strict = true)
|
||||
{
|
||||
global $db, $mybb, $plugins;
|
||||
|
||||
$this->get_login_data();
|
||||
|
||||
if(empty($this->login_data['username']))
|
||||
{
|
||||
// Username must be validated to apply a password to
|
||||
$this->invalid_combination();
|
||||
return false;
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'this' => &$this,
|
||||
'strict' => &$strict,
|
||||
);
|
||||
|
||||
$plugins->run_hooks('datahandler_login_verify_password_start', $args);
|
||||
|
||||
$user = &$this->data;
|
||||
|
||||
if(!$this->login_data['uid'] || $this->login_data['uid'] && !$this->login_data['salt'] && $strict == false)
|
||||
{
|
||||
$this->invalid_combination();
|
||||
}
|
||||
|
||||
if($strict == true)
|
||||
{
|
||||
if(!$this->login_data['salt'])
|
||||
{
|
||||
// Generate a salt for this user and assume the password stored in db is a plain md5 password
|
||||
$password_fields = create_password($this->login_data['password']);
|
||||
$this->login_data = array_merge($this->login_data, $password_fields);
|
||||
$db->update_query("users", $password_fields, "uid = '{$this->login_data['uid']}'");
|
||||
}
|
||||
|
||||
if(!$this->login_data['loginkey'])
|
||||
{
|
||||
$this->login_data['loginkey'] = generate_loginkey();
|
||||
|
||||
$sql_array = array(
|
||||
"loginkey" => $this->login_data['loginkey']
|
||||
);
|
||||
|
||||
$db->update_query("users", $sql_array, "uid = '{$this->login_data['uid']}'");
|
||||
}
|
||||
}
|
||||
|
||||
$plugins->run_hooks('datahandler_login_verify_password_end', $args);
|
||||
|
||||
if(!verify_user_password($this->login_data, $user['password']))
|
||||
{
|
||||
$this->invalid_combination(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $show_login_attempts
|
||||
*/
|
||||
function invalid_combination($show_login_attempts = false)
|
||||
{
|
||||
global $db, $lang, $mybb;
|
||||
|
||||
// Don't show an error when the captcha was wrong!
|
||||
if(!$this->captcha_verified)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$login_text = '';
|
||||
if($show_login_attempts)
|
||||
{
|
||||
if($mybb->settings['failedlogincount'] != 0 && $mybb->settings['failedlogintext'] == 1 && $this->login_data['uid'] != 0)
|
||||
{
|
||||
$logins = login_attempt_check($this->login_data['uid'], false) + 1;
|
||||
$login_text = $lang->sprintf($lang->failed_login_again, $mybb->settings['failedlogincount'] - $logins);
|
||||
}
|
||||
}
|
||||
|
||||
switch($mybb->settings['username_method'])
|
||||
{
|
||||
case 1:
|
||||
$this->set_error('invalidpwordusernameemail', $login_text);
|
||||
break;
|
||||
case 2:
|
||||
$this->set_error('invalidpwordusernamecombo', $login_text);
|
||||
break;
|
||||
default:
|
||||
$this->set_error('invalidpwordusername', $login_text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function get_login_data()
|
||||
{
|
||||
global $db, $settings;
|
||||
|
||||
$user = &$this->data;
|
||||
|
||||
$options = array(
|
||||
'fields' => '*',
|
||||
'username_method' => (int)$settings['username_method']
|
||||
);
|
||||
|
||||
if($this->username_method !== null)
|
||||
{
|
||||
$options['username_method'] = (int)$this->username_method;
|
||||
}
|
||||
|
||||
$this->login_data = get_user_by_username($user['username'], $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function validate_login()
|
||||
{
|
||||
global $plugins, $mybb;
|
||||
|
||||
$user = &$this->data;
|
||||
|
||||
$plugins->run_hooks('datahandler_login_validate_start', $this);
|
||||
|
||||
if(!defined('IN_ADMINCP'))
|
||||
{
|
||||
$this->verify_attempts($mybb->settings['captchaimage']);
|
||||
}
|
||||
|
||||
if(array_key_exists('username', $user))
|
||||
{
|
||||
$this->verify_username();
|
||||
}
|
||||
|
||||
if(array_key_exists('password', $user))
|
||||
{
|
||||
$this->verify_password();
|
||||
}
|
||||
|
||||
$plugins->run_hooks('datahandler_login_validate_end', $this);
|
||||
|
||||
$this->set_validated(true);
|
||||
if(count($this->get_errors()) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true
|
||||
*/
|
||||
function complete_login()
|
||||
{
|
||||
global $plugins, $db, $mybb, $session;
|
||||
|
||||
$user = &$this->login_data;
|
||||
|
||||
$plugins->run_hooks('datahandler_login_complete_start', $this);
|
||||
|
||||
// Login to MyBB
|
||||
my_setcookie('loginattempts', 1);
|
||||
my_setcookie("sid", $session->sid, -1, true);
|
||||
|
||||
$ip_address = $db->escape_binary($session->packedip);
|
||||
$db->delete_query("sessions", "ip = {$ip_address} AND sid != '{$session->sid}'");
|
||||
|
||||
$newsession = array(
|
||||
"uid" => $user['uid'],
|
||||
);
|
||||
|
||||
$db->update_query("sessions", $newsession, "sid = '{$session->sid}'");
|
||||
$db->update_query("users", array("loginattempts" => 1), "uid = '{$user['uid']}'");
|
||||
|
||||
$remember = null;
|
||||
if(!isset($mybb->input['remember']) || $mybb->input['remember'] != "yes")
|
||||
{
|
||||
$remember = -1;
|
||||
}
|
||||
|
||||
my_setcookie("mybbuser", $user['uid']."_".$user['loginkey'], $remember, true, "lax");
|
||||
|
||||
if($this->captcha !== false)
|
||||
{
|
||||
$this->captcha->invalidate_captcha();
|
||||
}
|
||||
|
||||
$plugins->run_hooks('datahandler_login_complete_end', $this);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
772
webroot/forum/inc/datahandlers/pm.php
Normal file
772
webroot/forum/inc/datahandlers/pm.php
Normal file
@@ -0,0 +1,772 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
/**
|
||||
* PM handling class, provides common structure to handle private messaging data.
|
||||
*
|
||||
*/
|
||||
class PMDataHandler extends DataHandler
|
||||
{
|
||||
/**
|
||||
* The language file used in the data handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language_file = 'datahandler_pm';
|
||||
|
||||
/**
|
||||
* The prefix for the language variables used in the data handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language_prefix = 'pmdata';
|
||||
|
||||
/**
|
||||
* Array of data inserted in to a private message.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $pm_insert_data = array();
|
||||
|
||||
/**
|
||||
* Array of data used to update a private message.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $pm_update_data = array();
|
||||
|
||||
/**
|
||||
* PM ID currently being manipulated by the datahandlers.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $pmid = 0;
|
||||
|
||||
/**
|
||||
* Values to be returned after inserting a PM.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $return_values = array();
|
||||
|
||||
/**
|
||||
* Verifies a private message subject.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function verify_subject()
|
||||
{
|
||||
$subject = &$this->data['subject'];
|
||||
|
||||
// Subject is over 85 characters, too long.
|
||||
if(my_strlen($subject) > 85)
|
||||
{
|
||||
$this->set_error("too_long_subject");
|
||||
return false;
|
||||
}
|
||||
// No subject, apply the default [no subject]
|
||||
if(!trim_blank_chrs($subject))
|
||||
{
|
||||
$this->set_error("missing_subject");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if a message for a PM is valid.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function verify_message()
|
||||
{
|
||||
$message = &$this->data['message'];
|
||||
|
||||
// No message, return an error.
|
||||
if(trim_blank_chrs($message) == '')
|
||||
{
|
||||
$this->set_error("missing_message");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the length of message is beyond SQL limitation for 'text' field
|
||||
else if(strlen($message) > 65535)
|
||||
{
|
||||
$this->set_error("message_too_long", array('65535', strlen($message)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the specified sender is valid or not.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function verify_sender()
|
||||
{
|
||||
global $db, $mybb, $lang;
|
||||
|
||||
$pm = &$this->data;
|
||||
|
||||
// Return if we've already validated
|
||||
if(!empty($pm['sender']))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetch the senders profile data.
|
||||
$sender = get_user($pm['fromid']);
|
||||
|
||||
// Collect user permissions for the sender.
|
||||
$sender_permissions = user_permissions($pm['fromid']);
|
||||
|
||||
// Check if the sender is over their quota or not - if they are, disable draft sending
|
||||
if(isset($pm['options']['savecopy']) && $pm['options']['savecopy'] != 0 && empty($pm['saveasdraft']))
|
||||
{
|
||||
if($sender_permissions['pmquota'] != 0 && $sender['totalpms'] >= $sender_permissions['pmquota'] && $this->admin_override != true)
|
||||
{
|
||||
$pm['options']['savecopy'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Assign the sender information to the data.
|
||||
$pm['sender'] = array(
|
||||
"uid" => $sender['uid'],
|
||||
"username" => $sender['username']
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if an array of recipients for a private message are valid
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function verify_recipient()
|
||||
{
|
||||
global $cache, $db, $mybb, $lang;
|
||||
|
||||
$pm = &$this->data;
|
||||
|
||||
$recipients = array();
|
||||
|
||||
$invalid_recipients = array();
|
||||
// We have our recipient usernames but need to fetch user IDs
|
||||
if(array_key_exists("to", $pm))
|
||||
{
|
||||
foreach(array("to", "bcc") as $recipient_type)
|
||||
{
|
||||
if(!isset($pm[$recipient_type]))
|
||||
{
|
||||
$pm[$recipient_type] = array();
|
||||
}
|
||||
if(!is_array($pm[$recipient_type]))
|
||||
{
|
||||
$pm[$recipient_type] = array($pm[$recipient_type]);
|
||||
}
|
||||
|
||||
$pm[$recipient_type] = array_map('trim', $pm[$recipient_type]);
|
||||
$pm[$recipient_type] = array_filter($pm[$recipient_type]);
|
||||
|
||||
// No recipients? Skip query
|
||||
if(empty($pm[$recipient_type]))
|
||||
{
|
||||
if($recipient_type == 'to' && !$pm['saveasdraft'])
|
||||
{
|
||||
$this->set_error("no_recipients");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$recipientUsernames = array_map(array($db, 'escape_string'), $pm[$recipient_type]);
|
||||
$recipientUsernames = "'".implode("','", $recipientUsernames)."'";
|
||||
|
||||
$query = $db->simple_select('users', '*', 'username IN('.$recipientUsernames.')');
|
||||
|
||||
$validUsernames = array();
|
||||
|
||||
while($user = $db->fetch_array($query))
|
||||
{
|
||||
if($recipient_type == "bcc")
|
||||
{
|
||||
$user['bcc'] = 1;
|
||||
}
|
||||
|
||||
$recipients[] = $user;
|
||||
$validUsernames[] = $user['username'];
|
||||
}
|
||||
|
||||
foreach($pm[$recipient_type] as $username)
|
||||
{
|
||||
if(!in_array($username, $validUsernames))
|
||||
{
|
||||
$invalid_recipients[] = $username;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// We have recipient IDs
|
||||
else
|
||||
{
|
||||
foreach(array("toid", "bccid") as $recipient_type)
|
||||
{
|
||||
if(!isset($pm[$recipient_type]))
|
||||
{
|
||||
$pm[$recipient_type] = array();
|
||||
}
|
||||
if(!is_array($pm[$recipient_type]))
|
||||
{
|
||||
$pm[$recipient_type] = array($pm[$recipient_type]);
|
||||
}
|
||||
$pm[$recipient_type] = array_map('intval', $pm[$recipient_type]);
|
||||
$pm[$recipient_type] = array_filter($pm[$recipient_type]);
|
||||
|
||||
// No recipients? Skip query
|
||||
if(empty($pm[$recipient_type]))
|
||||
{
|
||||
if($recipient_type == 'toid' && !$pm['saveasdraft'])
|
||||
{
|
||||
$this->set_error("no_recipients");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$recipientUids = "'".implode("','", $pm[$recipient_type])."'";
|
||||
|
||||
$query = $db->simple_select('users', '*', 'uid IN('.$recipientUids.')');
|
||||
|
||||
$validUids = array();
|
||||
|
||||
while($user = $db->fetch_array($query))
|
||||
{
|
||||
if($recipient_type == "bccid")
|
||||
{
|
||||
$user['bcc'] = 1;
|
||||
}
|
||||
|
||||
$recipients[] = $user;
|
||||
$validUids[] = $user['uid'];
|
||||
}
|
||||
|
||||
foreach($pm[$recipient_type] as $uid)
|
||||
{
|
||||
if(!in_array($uid, $validUids))
|
||||
{
|
||||
$invalid_recipients[] = $uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we have one or more invalid recipients and we're not saving a draft, error
|
||||
if(count($invalid_recipients) > 0)
|
||||
{
|
||||
$invalid_recipients = implode($lang->comma, array_map("htmlspecialchars_uni", $invalid_recipients));
|
||||
$this->set_error("invalid_recipients", array($invalid_recipients));
|
||||
return false;
|
||||
}
|
||||
|
||||
$sender_permissions = user_permissions($pm['fromid']);
|
||||
|
||||
// Are we trying to send this message to more users than the permissions allow?
|
||||
if($sender_permissions['maxpmrecipients'] > 0 && count($recipients) > $sender_permissions['maxpmrecipients'] && $this->admin_override != true)
|
||||
{
|
||||
$this->set_error("too_many_recipients", array($sender_permissions['maxpmrecipients']));
|
||||
}
|
||||
|
||||
// Now we're done with that we loop through each recipient
|
||||
foreach($recipients as $user)
|
||||
{
|
||||
// Collect group permissions for this recipient.
|
||||
$recipient_permissions = user_permissions($user['uid']);
|
||||
|
||||
// See if the sender is on the recipients ignore list and that either
|
||||
// - admin_override is set or
|
||||
// - sender is an administrator
|
||||
if($this->admin_override != true && $sender_permissions['canoverridepm'] != 1)
|
||||
{
|
||||
if(!empty($user['ignorelist']) && strpos(','.$user['ignorelist'].',', ','.$pm['fromid'].',') !== false)
|
||||
{
|
||||
$this->set_error("recipient_is_ignoring", array(htmlspecialchars_uni($user['username'])));
|
||||
}
|
||||
|
||||
// Is the recipient only allowing private messages from their buddy list?
|
||||
if(empty($pm['saveasdraft']) && $mybb->settings['allowbuddyonly'] == 1 && $user['receivefrombuddy'] == 1 && !empty($user['buddylist']) && strpos(','.$user['buddylist'].',', ','.$pm['fromid'].',') === false)
|
||||
{
|
||||
$this->set_error('recipient_has_buddy_only', array(htmlspecialchars_uni($user['username'])));
|
||||
}
|
||||
|
||||
// Can the recipient actually receive private messages based on their permissions or user setting?
|
||||
if(($user['receivepms'] == 0 || $recipient_permissions['canusepms'] == 0) && empty($pm['saveasdraft']))
|
||||
{
|
||||
$this->set_error("recipient_pms_disabled", array(htmlspecialchars_uni($user['username'])));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if the user has reached their private message quota - if they have, email them.
|
||||
if($recipient_permissions['pmquota'] != 0 && $user['totalpms'] >= $recipient_permissions['pmquota'] && $sender_permissions['cancp'] != 1 && empty($pm['saveasdraft']) && !$this->admin_override)
|
||||
{
|
||||
if(trim($user['language']) != '' && $lang->language_exists($user['language']))
|
||||
{
|
||||
$uselang = trim($user['language']);
|
||||
}
|
||||
elseif($mybb->settings['bblanguage'])
|
||||
{
|
||||
$uselang = $mybb->settings['bblanguage'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$uselang = "english";
|
||||
}
|
||||
if($uselang == $mybb->settings['bblanguage'] || !$uselang)
|
||||
{
|
||||
$emailsubject = $lang->emailsubject_reachedpmquota;
|
||||
$emailmessage = $lang->email_reachedpmquota;
|
||||
}
|
||||
else
|
||||
{
|
||||
$userlang = new MyLanguage;
|
||||
$userlang->set_path(MYBB_ROOT."inc/languages");
|
||||
$userlang->set_language($uselang);
|
||||
$userlang->load("messages");
|
||||
$emailsubject = $userlang->emailsubject_reachedpmquota;
|
||||
$emailmessage = $userlang->email_reachedpmquota;
|
||||
}
|
||||
$emailmessage = $lang->sprintf($emailmessage, $user['username'], $mybb->settings['bbname'], $mybb->settings['bburl']);
|
||||
$emailsubject = $lang->sprintf($emailsubject, $mybb->settings['bbname'], $pm['subject']);
|
||||
|
||||
$new_email = array(
|
||||
"mailto" => $db->escape_string($user['email']),
|
||||
"mailfrom" => '',
|
||||
"subject" => $db->escape_string($emailsubject),
|
||||
"message" => $db->escape_string($emailmessage),
|
||||
"headers" => ''
|
||||
);
|
||||
|
||||
$db->insert_query("mailqueue", $new_email);
|
||||
$cache->update_mailqueue();
|
||||
|
||||
if($this->admin_override != true)
|
||||
{
|
||||
$this->set_error("recipient_reached_quota", array(htmlspecialchars_uni($user['username'])));
|
||||
}
|
||||
}
|
||||
|
||||
// Everything looks good, assign some specifics about the recipient
|
||||
$pm['recipients'][$user['uid']] = array(
|
||||
"uid" => $user['uid'],
|
||||
"username" => $user['username'],
|
||||
"email" => $user['email'],
|
||||
"lastactive" => $user['lastactive'],
|
||||
"pmnotice" => $user['pmnotice'],
|
||||
"pmnotify" => $user['pmnotify'],
|
||||
"language" => $user['language']
|
||||
);
|
||||
|
||||
// If this recipient is defined as a BCC recipient, save it
|
||||
if(isset($user['bcc']) && $user['bcc'] == 1)
|
||||
{
|
||||
$pm['recipients'][$user['uid']]['bcc'] = 1;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the user is not flooding the system.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function verify_pm_flooding()
|
||||
{
|
||||
global $mybb, $db;
|
||||
|
||||
$pm = &$this->data;
|
||||
|
||||
// Check if post flooding is enabled within MyBB or if the admin override option is specified.
|
||||
if($mybb->settings['pmfloodsecs'] > 0 && $pm['fromid'] != 0 && $this->admin_override == false && !is_moderator(0, '', $pm['fromid']))
|
||||
{
|
||||
// Fetch the senders profile data.
|
||||
$sender = get_user($pm['fromid']);
|
||||
|
||||
// Calculate last post
|
||||
$query = $db->simple_select("privatemessages", "dateline", "fromid='".$db->escape_string($pm['fromid'])."' AND toid != '0'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit' => 1));
|
||||
$sender['lastpm'] = $db->fetch_field($query, "dateline");
|
||||
|
||||
// A little bit of calculation magic and moderator status checking.
|
||||
if(TIME_NOW-$sender['lastpm'] <= $mybb->settings['pmfloodsecs'])
|
||||
{
|
||||
// Oops, user has been flooding - throw back error message.
|
||||
$time_to_wait = ($mybb->settings['pmfloodsecs'] - (TIME_NOW-$sender['lastpm'])) + 1;
|
||||
if($time_to_wait == 1)
|
||||
{
|
||||
$this->set_error("pm_flooding_one_second");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->set_error("pm_flooding", array($time_to_wait));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// All is well that ends well - return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the various 'options' for sending PMs are valid.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function verify_options()
|
||||
{
|
||||
$options = &$this->data['options'];
|
||||
|
||||
$this->verify_yesno_option($options, 'signature', 1);
|
||||
$this->verify_yesno_option($options, 'savecopy', 1);
|
||||
$this->verify_yesno_option($options, 'disablesmilies', 0);
|
||||
|
||||
// Requesting a read receipt?
|
||||
if(isset($options['readreceipt']) && $options['readreceipt'] == 1)
|
||||
{
|
||||
$options['readreceipt'] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$options['readreceipt'] = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an entire private message.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function validate_pm()
|
||||
{
|
||||
global $plugins;
|
||||
|
||||
$pm = &$this->data;
|
||||
|
||||
if(empty($pm['savedraft']))
|
||||
{
|
||||
$this->verify_pm_flooding();
|
||||
}
|
||||
|
||||
// Verify all PM assets.
|
||||
$this->verify_subject();
|
||||
|
||||
$this->verify_sender();
|
||||
|
||||
$this->verify_recipient();
|
||||
|
||||
$this->verify_message();
|
||||
|
||||
$this->verify_options();
|
||||
|
||||
$plugins->run_hooks("datahandler_pm_validate", $this);
|
||||
|
||||
// Choose the appropriate folder to save in.
|
||||
if(!empty($pm['saveasdraft']))
|
||||
{
|
||||
$pm['folder'] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pm['folder'] = 1;
|
||||
}
|
||||
|
||||
// We are done validating, return.
|
||||
$this->set_validated(true);
|
||||
if(count($this->get_errors()) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new private message.
|
||||
*
|
||||
* @return array Array of PM useful data.
|
||||
*/
|
||||
function insert_pm()
|
||||
{
|
||||
global $cache, $db, $mybb, $plugins, $lang;
|
||||
|
||||
// Yes, validating is required.
|
||||
if(!$this->get_validated())
|
||||
{
|
||||
die("The PM needs to be validated before inserting it into the DB.");
|
||||
}
|
||||
if(count($this->get_errors()) > 0)
|
||||
{
|
||||
die("The PM is not valid.");
|
||||
}
|
||||
|
||||
// Assign data to common variable
|
||||
$pm = &$this->data;
|
||||
|
||||
if(empty($pm['pmid']))
|
||||
{
|
||||
$pm['pmid'] = 0;
|
||||
}
|
||||
$pm['pmid'] = (int)$pm['pmid'];
|
||||
|
||||
if(empty($pm['icon']) || $pm['icon'] < 0)
|
||||
{
|
||||
$pm['icon'] = 0;
|
||||
}
|
||||
|
||||
$uid = 0;
|
||||
|
||||
if(!is_array($pm['recipients']))
|
||||
{
|
||||
$recipient_list = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Build recipient list
|
||||
foreach($pm['recipients'] as $recipient)
|
||||
{
|
||||
if(!empty($recipient['bcc']))
|
||||
{
|
||||
$recipient_list['bcc'][] = $recipient['uid'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$recipient_list['to'][] = $recipient['uid'];
|
||||
$uid = $recipient['uid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->pm_insert_data = array(
|
||||
'fromid' => (int)$pm['sender']['uid'],
|
||||
'folder' => $pm['folder'],
|
||||
'subject' => $db->escape_string($pm['subject']),
|
||||
'icon' => (int)$pm['icon'],
|
||||
'message' => $db->escape_string($pm['message']),
|
||||
'dateline' => TIME_NOW,
|
||||
'status' => 0,
|
||||
'includesig' => $pm['options']['signature'],
|
||||
'smilieoff' => $pm['options']['disablesmilies'],
|
||||
'receipt' => (int)$pm['options']['readreceipt'],
|
||||
'readtime' => 0,
|
||||
'recipients' => $db->escape_string(my_serialize($recipient_list)),
|
||||
'ipaddress' => $db->escape_binary($pm['ipaddress'])
|
||||
);
|
||||
|
||||
// Check if we're updating a draft or not.
|
||||
$query = $db->simple_select("privatemessages", "pmid, deletetime", "folder='3' AND uid='".(int)$pm['sender']['uid']."' AND pmid='{$pm['pmid']}'");
|
||||
$draftcheck = $db->fetch_array($query);
|
||||
|
||||
// This PM was previously a draft
|
||||
if($draftcheck['pmid'])
|
||||
{
|
||||
if($draftcheck['deletetime'])
|
||||
{
|
||||
// This draft was a reply to a PM
|
||||
$pm['pmid'] = $draftcheck['deletetime'];
|
||||
$pm['do'] = "reply";
|
||||
}
|
||||
|
||||
// Delete the old draft as we no longer need it
|
||||
$db->delete_query("privatemessages", "pmid='{$draftcheck['pmid']}'");
|
||||
}
|
||||
|
||||
// Saving this message as a draft
|
||||
if(!empty($pm['saveasdraft']))
|
||||
{
|
||||
$this->pm_insert_data['uid'] = $pm['sender']['uid'];
|
||||
|
||||
// If this is a reply, then piggyback into the deletetime to let us know in the future
|
||||
if($pm['do'] == "reply" || $pm['do'] == "replyall")
|
||||
{
|
||||
$this->pm_insert_data['deletetime'] = $pm['pmid'];
|
||||
}
|
||||
|
||||
$plugins->run_hooks("datahandler_pm_insert_updatedraft", $this);
|
||||
|
||||
$this->pmid = $db->insert_query("privatemessages", $this->pm_insert_data);
|
||||
|
||||
$plugins->run_hooks("datahandler_pm_insert_updatedraft_commit", $this);
|
||||
|
||||
// If this is a draft, end it here - below deals with complete messages
|
||||
return array(
|
||||
"draftsaved" => 1
|
||||
);
|
||||
}
|
||||
|
||||
$this->pmid = array();
|
||||
|
||||
// Save a copy of the PM for each of our recipients
|
||||
foreach($pm['recipients'] as $recipient)
|
||||
{
|
||||
// Send email notification of new PM if it is enabled for the recipient
|
||||
$query = $db->simple_select("privatemessages", "dateline", "uid='".$recipient['uid']."' AND folder='1'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit' => 1));
|
||||
$lastpm = $db->fetch_array($query);
|
||||
if($recipient['pmnotify'] == 1 && $recipient['lastactive'] > $lastpm['dateline'])
|
||||
{
|
||||
if($recipient['language'] != "" && $lang->language_exists($recipient['language']))
|
||||
{
|
||||
$uselang = $recipient['language'];
|
||||
}
|
||||
elseif($mybb->settings['bblanguage'])
|
||||
{
|
||||
$uselang = $mybb->settings['bblanguage'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$uselang = "english";
|
||||
}
|
||||
if($uselang == $mybb->settings['bblanguage'] && !empty($lang->emailsubject_newpm))
|
||||
{
|
||||
$emailsubject = $lang->emailsubject_newpm;
|
||||
$emailmessage = $lang->email_newpm;
|
||||
}
|
||||
else
|
||||
{
|
||||
$userlang = new MyLanguage;
|
||||
$userlang->set_path(MYBB_ROOT."inc/languages");
|
||||
$userlang->set_language($uselang);
|
||||
$userlang->load("messages");
|
||||
$emailsubject = $userlang->emailsubject_newpm;
|
||||
$emailmessage = $userlang->email_newpm;
|
||||
}
|
||||
|
||||
if(!$pm['sender']['username'])
|
||||
{
|
||||
$pm['sender']['username'] = $lang->mybb_engine;
|
||||
}
|
||||
|
||||
require_once MYBB_ROOT.'inc/class_parser.php';
|
||||
$parser = new Postparser;
|
||||
|
||||
$parser_options = array(
|
||||
'me_username' => $pm['sender']['username'],
|
||||
'filter_badwords' => 1
|
||||
);
|
||||
|
||||
$pm['message'] = $parser->text_parse_message($pm['message'], $parser_options);
|
||||
|
||||
$emailmessage = $lang->sprintf($emailmessage, $recipient['username'], $pm['sender']['username'], $mybb->settings['bbname'], $mybb->settings['bburl'], $pm['message']);
|
||||
$emailsubject = $lang->sprintf($emailsubject, $mybb->settings['bbname'], $pm['subject']);
|
||||
|
||||
$new_email = array(
|
||||
"mailto" => $db->escape_string($recipient['email']),
|
||||
"mailfrom" => '',
|
||||
"subject" => $db->escape_string($emailsubject),
|
||||
"message" => $db->escape_string($emailmessage),
|
||||
"headers" => ''
|
||||
);
|
||||
|
||||
$db->insert_query("mailqueue", $new_email);
|
||||
$cache->update_mailqueue();
|
||||
}
|
||||
|
||||
$this->pm_insert_data['uid'] = $recipient['uid'];
|
||||
$this->pm_insert_data['toid'] = $recipient['uid'];
|
||||
|
||||
$plugins->run_hooks("datahandler_pm_insert", $this);
|
||||
|
||||
$this->pmid[] = $db->insert_query("privatemessages", $this->pm_insert_data);
|
||||
|
||||
$plugins->run_hooks("datahandler_pm_insert_commit", $this);
|
||||
|
||||
// If PM noices/alerts are on, show!
|
||||
if($recipient['pmnotice'] == 1)
|
||||
{
|
||||
$updated_user = array(
|
||||
"pmnotice" => 2
|
||||
);
|
||||
$db->update_query("users", $updated_user, "uid='{$recipient['uid']}'");
|
||||
}
|
||||
|
||||
// Update private message count (total, new and unread) for recipient
|
||||
require_once MYBB_ROOT."/inc/functions_user.php";
|
||||
update_pm_count($recipient['uid'], 7, $recipient['lastactive']);
|
||||
}
|
||||
|
||||
// Are we replying or forwarding an existing PM?
|
||||
if($pm['pmid'])
|
||||
{
|
||||
if($pm['do'] == "reply" || $pm['do'] == "replyall")
|
||||
{
|
||||
$sql_array = array(
|
||||
'status' => 3,
|
||||
'statustime' => TIME_NOW
|
||||
);
|
||||
$db->update_query("privatemessages", $sql_array, "pmid={$pm['pmid']} AND uid={$pm['sender']['uid']}");
|
||||
}
|
||||
elseif($pm['do'] == "forward")
|
||||
{
|
||||
$sql_array = array(
|
||||
'status' => 4,
|
||||
'statustime' => TIME_NOW
|
||||
);
|
||||
$db->update_query("privatemessages", $sql_array, "pmid={$pm['pmid']} AND uid={$pm['sender']['uid']}");
|
||||
}
|
||||
}
|
||||
|
||||
// If we're saving a copy
|
||||
if($pm['options']['savecopy'] != 0)
|
||||
{
|
||||
if(isset($recipient_list['to']) && is_array($recipient_list['to']) && count($recipient_list['to']) == 1)
|
||||
{
|
||||
$this->pm_insert_data['toid'] = $uid;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->pm_insert_data['toid'] = 0;
|
||||
}
|
||||
$this->pm_insert_data['uid'] = (int)$pm['sender']['uid'];
|
||||
$this->pm_insert_data['folder'] = 2;
|
||||
$this->pm_insert_data['status'] = 1;
|
||||
$this->pm_insert_data['receipt'] = 0;
|
||||
|
||||
$plugins->run_hooks("datahandler_pm_insert_savedcopy", $this);
|
||||
|
||||
$db->insert_query("privatemessages", $this->pm_insert_data);
|
||||
|
||||
$plugins->run_hooks("datahandler_pm_insert_savedcopy_commit", $this);
|
||||
|
||||
// Because the sender saved a copy, update their total pm count
|
||||
require_once MYBB_ROOT."/inc/functions_user.php";
|
||||
update_pm_count($pm['sender']['uid'], 1);
|
||||
}
|
||||
|
||||
// Return back with appropriate data
|
||||
$this->return_values = array(
|
||||
"messagesent" => 1,
|
||||
"pmids" => $this->pmid
|
||||
);
|
||||
|
||||
$plugins->run_hooks("datahandler_pm_insert_end", $this);
|
||||
|
||||
return $this->return_values;
|
||||
}
|
||||
}
|
||||
1984
webroot/forum/inc/datahandlers/post.php
Normal file
1984
webroot/forum/inc/datahandlers/post.php
Normal file
File diff suppressed because it is too large
Load Diff
1861
webroot/forum/inc/datahandlers/user.php
Normal file
1861
webroot/forum/inc/datahandlers/user.php
Normal file
File diff suppressed because it is too large
Load Diff
741
webroot/forum/inc/datahandlers/warnings.php
Normal file
741
webroot/forum/inc/datahandlers/warnings.php
Normal file
@@ -0,0 +1,741 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Login handling class, provides common structure to handle login events.
|
||||
*
|
||||
*/
|
||||
class WarningsHandler extends DataHandler
|
||||
{
|
||||
/**
|
||||
* The language file used in the data handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language_file = 'datahandler_warnings';
|
||||
|
||||
/**
|
||||
* The prefix for the language variables used in the data handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language_prefix = 'warnings';
|
||||
|
||||
/**
|
||||
* The stored data for the warning being written.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $write_warning_data = array();
|
||||
|
||||
/**
|
||||
* The stored data for the warning being retrieved.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $read_warning_data = array();
|
||||
|
||||
/**
|
||||
* Friendly redirect action after inserting a new warning.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $friendly_action = '';
|
||||
|
||||
/**
|
||||
* Validate a warning user assets.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function validate_user()
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
$warning = &$this->data;
|
||||
|
||||
$user = get_user($warning['uid']);
|
||||
|
||||
if(!$user['uid'])
|
||||
{
|
||||
$this->set_error('error_invalid_user');
|
||||
return false;
|
||||
}
|
||||
|
||||
if($user['uid'] == $mybb->user['uid'])
|
||||
{
|
||||
$this->set_error('error_cannot_warn_self');
|
||||
return false;
|
||||
}
|
||||
|
||||
if($user['warningpoints'] >= $mybb->settings['maxwarningpoints'])
|
||||
{
|
||||
$this->set_error('error_user_reached_max_warning');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a warning post.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function validate_post()
|
||||
{
|
||||
$warning = &$this->data;
|
||||
|
||||
$post = get_post($warning['pid']);
|
||||
|
||||
if(!$post['pid'])
|
||||
{
|
||||
$this->set_error('error_invalid_post');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a warning notes.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function validate_notes()
|
||||
{
|
||||
$warning = &$this->data;
|
||||
|
||||
if(!trim($warning['notes']))
|
||||
{
|
||||
$this->set_error('error_no_note');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate maximum warnings per day for current user.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function validate_maximum()
|
||||
{
|
||||
global $mybb, $db, $lang;
|
||||
|
||||
if($mybb->usergroup['maxwarningsday'] != 0)
|
||||
{
|
||||
$timecut = TIME_NOW-60*60*24;
|
||||
$query = $db->simple_select("warnings", "COUNT(wid) AS given_today", "issuedby='{$mybb->user['uid']}' AND dateline>'$timecut'");
|
||||
$given_today = $db->fetch_field($query, "given_today");
|
||||
if($given_today >= $mybb->usergroup['maxwarningsday'])
|
||||
{
|
||||
$this->set_error('reached_max_warnings_day', array(my_number_format($mybb->usergroup['maxwarningsday'])));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate warnings type.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function validate_type()
|
||||
{
|
||||
global $mybb, $db;
|
||||
|
||||
$warning = &$this->data;
|
||||
|
||||
// Issuing a custom warning
|
||||
if($warning['type'] == 'custom')
|
||||
{
|
||||
if($mybb->settings['allowcustomwarnings'] == 0)
|
||||
{
|
||||
$this->set_error('error_cant_custom_warn');
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!$warning['custom_reason'])
|
||||
{
|
||||
$this->set_error('error_no_custom_reason');
|
||||
return false;
|
||||
}
|
||||
|
||||
$warning['title'] = $warning['custom_reason'];
|
||||
|
||||
if(!$warning['custom_points'] || $warning['custom_points'] > $mybb->settings['maxwarningpoints'] || $warning['custom_points'] < 0)
|
||||
{
|
||||
$this->set_error('error_invalid_custom_points', array(my_number_format($mybb->settings['maxwarningpoints'])));
|
||||
return false;
|
||||
}
|
||||
|
||||
$warning['points'] = round($warning['custom_points']);
|
||||
|
||||
// Build expiry date
|
||||
if($warning['expires_period'] == "hours")
|
||||
{
|
||||
$warning['expires'] = $warning['expires']*3600 + TIME_NOW;
|
||||
}
|
||||
else if($warning['expires_period'] == "days")
|
||||
{
|
||||
$warning['expires'] = $warning['expires']*86400 + TIME_NOW;
|
||||
}
|
||||
else if($warning['expires_period'] == "weeks")
|
||||
{
|
||||
$warning['expires'] = $warning['expires']*604800 + TIME_NOW;
|
||||
}
|
||||
else if($warning['expires_period'] == "months")
|
||||
{
|
||||
$warning['expires'] = $warning['expires']*2592000 + TIME_NOW;
|
||||
}
|
||||
else if($warning['expires_period'] == "never")
|
||||
{
|
||||
$warning['expires'] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unkown expires_period
|
||||
$this->set_error('error_invalid_expires_period');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Using a predefined warning type
|
||||
else
|
||||
{
|
||||
$query = $db->simple_select("warningtypes", "*", "tid='".(int)$warning['type']."'");
|
||||
$this->warning_type = $db->fetch_array($query);
|
||||
|
||||
if(!$this->warning_type)
|
||||
{
|
||||
$this->set_error('error_invalid_type');
|
||||
return false;
|
||||
}
|
||||
|
||||
$warning['points'] = $this->warning_type['points'];
|
||||
$warning['title'] = '';
|
||||
$warning['expires'] = 0;
|
||||
|
||||
if($this->warning_type['expirationtime'])
|
||||
{
|
||||
$warning['expires'] = TIME_NOW+$this->warning_type['expirationtime'];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a warning.
|
||||
*
|
||||
* @return boolean True when valid, false when invalid.
|
||||
*/
|
||||
function validate_warning()
|
||||
{
|
||||
global $plugins;
|
||||
|
||||
$warning = &$this->data;
|
||||
|
||||
// Verify all warning assets.
|
||||
$this->validate_user();
|
||||
$this->validate_maximum();
|
||||
$this->validate_notes();
|
||||
|
||||
if(array_key_exists('pid', $warning))
|
||||
{
|
||||
$this->validate_post();
|
||||
}
|
||||
if(array_key_exists('type', $warning))
|
||||
{
|
||||
$this->validate_type();
|
||||
}
|
||||
|
||||
$plugins->run_hooks("datahandler_warnings_validate_warning", $this);
|
||||
|
||||
// We are done validating, return.
|
||||
$this->set_validated(true);
|
||||
|
||||
if(count($this->get_errors()) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a valid warning from the DB engine.
|
||||
*
|
||||
* @param int $wid
|
||||
* @return array|bool array when valid, boolean false when invalid.
|
||||
*/
|
||||
function get($wid)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$wid = (int)$wid;
|
||||
if($wid <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = $db->simple_select("warnings", "*", "wid='".$wid."'");
|
||||
$this->read_warning_data = $db->fetch_array($query);
|
||||
|
||||
if(!$this->read_warning_data['wid'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->read_warning_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expire old warnings in the database.
|
||||
*
|
||||
* @return boolean True when finished.
|
||||
*/
|
||||
function expire_warnings()
|
||||
{
|
||||
global $db;
|
||||
|
||||
$users = array();
|
||||
|
||||
$query = $db->query("
|
||||
SELECT w.wid, w.uid, w.points, u.warningpoints
|
||||
FROM ".TABLE_PREFIX."warnings w
|
||||
LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=w.uid)
|
||||
WHERE expires<".TIME_NOW." AND expires!=0 AND expired!=1
|
||||
");
|
||||
while($warning = $db->fetch_array($query))
|
||||
{
|
||||
$updated_warning = array(
|
||||
"expired" => 1
|
||||
);
|
||||
$db->update_query("warnings", $updated_warning, "wid='{$warning['wid']}'");
|
||||
|
||||
if(array_key_exists($warning['uid'], $users))
|
||||
{
|
||||
$users[$warning['uid']] -= $warning['points'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$users[$warning['uid']] = $warning['warningpoints']-$warning['points'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach($users as $uid => $warningpoints)
|
||||
{
|
||||
if($warningpoints < 0)
|
||||
{
|
||||
$warningpoints = 0;
|
||||
}
|
||||
|
||||
$updated_user = array(
|
||||
"warningpoints" => (int)$warningpoints
|
||||
);
|
||||
$db->update_query("users", $updated_user, "uid='".(int)$uid."'");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an user warning details.
|
||||
*
|
||||
* @return array Updated user details.
|
||||
*/
|
||||
function update_user($method='insert')
|
||||
{
|
||||
global $db, $mybb, $lang, $cache, $groupscache;
|
||||
|
||||
if($mybb->settings['maxwarningpoints'] < 1)
|
||||
{
|
||||
$mybb->settings['maxwarningpoints'] = 10;
|
||||
}
|
||||
|
||||
if(!is_array($groupscache))
|
||||
{
|
||||
$groupscache = $cache->read("usergroups");
|
||||
}
|
||||
|
||||
$warning = &$this->data;
|
||||
|
||||
$user = get_user($warning['uid']);
|
||||
|
||||
if($method == 'insert')
|
||||
{
|
||||
// Build warning level & ensure it doesn't go over 100.
|
||||
$current_level = round($user['warningpoints']/$mybb->settings['maxwarningpoints']*100);
|
||||
$this->new_warning_level = round(($user['warningpoints']+$warning['points'])/$mybb->settings['maxwarningpoints']*100);
|
||||
if($this->new_warning_level > 100)
|
||||
{
|
||||
$this->new_warning_level = 100;
|
||||
}
|
||||
|
||||
// Update user
|
||||
$this->updated_user = array(
|
||||
"warningpoints" => $user['warningpoints']+$warning['points']
|
||||
);
|
||||
|
||||
// Fetch warning level
|
||||
$query = $db->simple_select("warninglevels", "*", "percentage<={$this->new_warning_level}", array("order_by" => "percentage", "order_dir" => "desc"));
|
||||
$new_level = $db->fetch_array($query);
|
||||
|
||||
if($new_level['lid'])
|
||||
{
|
||||
$expiration = 0;
|
||||
$action = my_unserialize($new_level['action']);
|
||||
|
||||
if($action['length'] > 0)
|
||||
{
|
||||
$expiration = TIME_NOW+$action['length'];
|
||||
}
|
||||
|
||||
switch($action['type'])
|
||||
{
|
||||
// Ban the user for a specified time
|
||||
case 1:
|
||||
// Fetch any previous bans for this user
|
||||
$query = $db->simple_select("banned", "*", "uid='{$user['uid']}' AND gid='{$action['usergroup']}' AND lifted>".TIME_NOW);
|
||||
$existing_ban = $db->fetch_array($query);
|
||||
|
||||
// Only perform if no previous ban or new ban expires later than existing ban
|
||||
if(($expiration > $existing_ban['lifted'] && $existing_ban['lifted'] != 0) || $expiration == 0 || !$existing_ban['uid'])
|
||||
{
|
||||
if(!$warning['title'])
|
||||
{
|
||||
$warning['title'] = $this->warning_type['title'];
|
||||
}
|
||||
|
||||
// Never lift the ban?
|
||||
if($action['length'] <= 0)
|
||||
{
|
||||
$bantime = '---';
|
||||
}
|
||||
else
|
||||
{
|
||||
$bantimes = fetch_ban_times();
|
||||
foreach($bantimes as $date => $string)
|
||||
{
|
||||
if($date == '---')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$time = 0;
|
||||
list($day, $month, $year) = explode('-', $date);
|
||||
if($day > 0)
|
||||
{
|
||||
$time += 60*60*24*$day;
|
||||
}
|
||||
|
||||
if($month > 0)
|
||||
{
|
||||
$time += 60*60*24*30*$month;
|
||||
}
|
||||
|
||||
if($year > 0)
|
||||
{
|
||||
$time += 60*60*24*365*$year;
|
||||
}
|
||||
|
||||
if($time == $action['length'])
|
||||
{
|
||||
$bantime = $date;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$new_ban = array(
|
||||
"uid" => $user['uid'],
|
||||
"gid" => $action['usergroup'],
|
||||
"oldgroup" => $user['usergroup'],
|
||||
"oldadditionalgroups" => $user['additionalgroups'],
|
||||
"olddisplaygroup" => $user['displaygroup'],
|
||||
"admin" => $mybb->user['uid'],
|
||||
"dateline" => TIME_NOW,
|
||||
"bantime" => $db->escape_string($bantime),
|
||||
"lifted" => $expiration,
|
||||
"reason" => $db->escape_string($warning['title'])
|
||||
);
|
||||
// Delete old ban for this user, taking details
|
||||
if($existing_ban['uid'])
|
||||
{
|
||||
$db->delete_query("banned", "uid='{$user['uid']}' AND gid='{$action['usergroup']}'");
|
||||
// Override new ban details with old group info
|
||||
$new_ban['oldgroup'] = $existing_ban['oldgroup'];
|
||||
$new_ban['oldadditionalgroups'] = $existing_ban['oldadditionalgroups'];
|
||||
$new_ban['olddisplaygroup'] = $existing_ban['olddisplaygroup'];
|
||||
}
|
||||
|
||||
$period = $lang->expiration_never;
|
||||
$ban_length = fetch_friendly_expiration($action['length']);
|
||||
|
||||
if($ban_length['time'])
|
||||
{
|
||||
$lang_str = "expiration_".$ban_length['period'];
|
||||
$period = $lang->sprintf($lang->result_period, $ban_length['time'], $lang->$lang_str);
|
||||
}
|
||||
|
||||
$group_name = $groupscache[$action['usergroup']]['title'];
|
||||
$this->friendly_action = $lang->sprintf($lang->redirect_warned_banned, $group_name, $period);
|
||||
|
||||
$db->insert_query("banned", $new_ban);
|
||||
$this->updated_user['usergroup'] = $action['usergroup'];
|
||||
$this->updated_user['additionalgroups'] = '';
|
||||
$this->updated_user['displaygroup'] = 0;
|
||||
}
|
||||
break;
|
||||
// Suspend posting privileges
|
||||
case 2:
|
||||
// Only perform if the expiration time is greater than the users current suspension period
|
||||
if($expiration == 0 || $expiration > $user['suspensiontime'])
|
||||
{
|
||||
if(($user['suspensiontime'] != 0 && $user['suspendposting']) || !$user['suspendposting'])
|
||||
{
|
||||
$period = $lang->expiration_never;
|
||||
$ban_length = fetch_friendly_expiration($action['length']);
|
||||
|
||||
if($ban_length['time'])
|
||||
{
|
||||
$lang_str = "expiration_".$ban_length['period'];
|
||||
$period = $lang->sprintf($lang->result_period, $ban_length['time'], $lang->$lang_str);
|
||||
}
|
||||
|
||||
$this->friendly_action = $lang->sprintf($lang->redirect_warned_suspended, $period);
|
||||
|
||||
$this->updated_user['suspensiontime'] = $expiration;
|
||||
$this->updated_user['suspendposting'] = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Moderate new posts
|
||||
case 3:
|
||||
// Only perform if the expiration time is greater than the users current suspension period
|
||||
if($expiration == 0 || $expiration > $user['moderationtime'])
|
||||
{
|
||||
if(($user['moderationtime'] != 0 && $user['moderateposts']) || !$user['suspendposting'])
|
||||
{
|
||||
$period = $lang->expiration_never;
|
||||
$ban_length = fetch_friendly_expiration($action['length']);
|
||||
|
||||
if($ban_length['time'])
|
||||
{
|
||||
$lang_str = "expiration_".$ban_length['period'];
|
||||
$period = $lang->sprintf($lang->result_period, $ban_length['time'], $lang->$lang_str);
|
||||
}
|
||||
|
||||
$this->friendly_action = $lang->sprintf($lang->redirect_warned_moderate, $period);
|
||||
|
||||
$this->updated_user['moderationtime'] = $expiration;
|
||||
$this->updated_user['moderateposts'] = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Warning is still active, lower users point count
|
||||
if($warning['expired'] != 1)
|
||||
{
|
||||
$new_warning_points = $user['warningpoints']-$warning['points'];
|
||||
if($new_warning_points < 0)
|
||||
{
|
||||
$new_warning_points = 0;
|
||||
}
|
||||
|
||||
$this->updated_user = array(
|
||||
"warningpoints" => $new_warning_points
|
||||
);
|
||||
|
||||
|
||||
// check if we need to revoke any consequences with this warning
|
||||
$current_level = round($user['warningpoints']/$mybb->settings['maxwarningpoints']*100);
|
||||
$this->new_warning_level = round($new_warning_points/$mybb->settings['maxwarningpoints']*100);
|
||||
$query = $db->simple_select("warninglevels", "action", "percentage>{$this->new_warning_level} AND percentage<=$current_level");
|
||||
if($db->num_rows($query))
|
||||
{
|
||||
// we have some warning levels we need to revoke
|
||||
$max_expiration_times = $check_levels = array();
|
||||
find_warnlevels_to_check($query, $max_expiration_times, $check_levels);
|
||||
|
||||
// now check warning levels already applied to this user to see if we need to lower any expiration times
|
||||
$query = $db->simple_select("warninglevels", "action", "percentage<={$this->new_warning_level}");
|
||||
$lower_expiration_times = $lower_levels = array();
|
||||
find_warnlevels_to_check($query, $lower_expiration_times, $lower_levels);
|
||||
|
||||
// now that we've got all the info, do necessary stuff
|
||||
for($i = 1; $i <= 3; ++$i)
|
||||
{
|
||||
if($check_levels[$i])
|
||||
{
|
||||
switch($i)
|
||||
{
|
||||
case 1: // Ban
|
||||
// we'll have to resort to letting the admin/mod remove the ban manually, since there's an issue if stacked bans are in force...
|
||||
continue 2;
|
||||
case 2: // Revoke posting
|
||||
$current_expiry_field = 'suspensiontime';
|
||||
$current_inforce_field = 'suspendposting';
|
||||
break;
|
||||
case 3:
|
||||
$current_expiry_field = 'moderationtime';
|
||||
$current_inforce_field = 'moderateposts';
|
||||
break;
|
||||
}
|
||||
|
||||
// if the thing isn't in force, don't bother with trying to update anything
|
||||
if(!$user[$current_inforce_field])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if($lower_levels[$i])
|
||||
{
|
||||
// lessen the expiration time if necessary
|
||||
|
||||
if(!$lower_expiration_times[$i])
|
||||
{
|
||||
// doesn't expire - enforce this
|
||||
$this->updated_user[$current_expiry_field] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if($max_expiration_times[$i])
|
||||
{
|
||||
// if the old level did have an expiry time...
|
||||
if($max_expiration_times[$i] <= $lower_expiration_times[$i])
|
||||
{
|
||||
// if the lower expiration time is actually higher than the upper expiration time -> skip
|
||||
continue;
|
||||
}
|
||||
// both new and old max expiry times aren't infinite, so we can take a difference
|
||||
$expire_offset = ($lower_expiration_times[$i] - $max_expiration_times[$i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the old level never expired, not much we can do but try to estimate a new expiry time... which will just happen to be starting from today...
|
||||
$expire_offset = TIME_NOW + $lower_expiration_times[$i];
|
||||
// if the user's expiry time is already less than what we're going to set it to, skip
|
||||
if($user[$current_expiry_field] <= $expire_offset)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$this->updated_user[$current_expiry_field] = $user[$current_expiry_field] + $expire_offset;
|
||||
// double-check if it's expired already
|
||||
if($this->updated_user[$current_expiry_field] < TIME_NOW)
|
||||
{
|
||||
$this->updated_user[$current_expiry_field] = 0;
|
||||
$this->updated_user[$current_inforce_field] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// there's no lower level for this type - remove the consequence entirely
|
||||
$this->updated_user[$current_expiry_field] = 0;
|
||||
$this->updated_user[$current_inforce_field] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save updated details
|
||||
$db->update_query("users", $this->updated_user, "uid='{$user['uid']}'");
|
||||
|
||||
$mybb->cache->update_moderators();
|
||||
|
||||
return $this->updated_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a warning into the database
|
||||
*
|
||||
* @return array Warning database details.
|
||||
*/
|
||||
function insert_warning()
|
||||
{
|
||||
global $db, $mybb, $plugins;
|
||||
|
||||
$warning = &$this->data;
|
||||
|
||||
$this->write_warning_data = array(
|
||||
"uid" => (int)$warning['uid'],
|
||||
"tid" => (int)$warning['type'],
|
||||
"pid" => (int)$warning['pid'],
|
||||
"title" => $db->escape_string($warning['title']),
|
||||
"points" => (int)$warning['points'],
|
||||
"dateline" => TIME_NOW,
|
||||
"issuedby" => $mybb->user['uid'],
|
||||
"expires" => (int)$warning['expires'],
|
||||
"expired" => 0,
|
||||
"revokereason" => '',
|
||||
"notes" => $db->escape_string($warning['notes'])
|
||||
);
|
||||
|
||||
$this->write_warning_data['wid'] = $db->insert_query("warnings", $this->write_warning_data);
|
||||
|
||||
$this->update_user();
|
||||
|
||||
$plugins->run_hooks("datahandler_warnings_insert_warning", $this);
|
||||
|
||||
return $this->write_warning_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a warning in the database
|
||||
*
|
||||
* @return array Warning database details.
|
||||
*/
|
||||
function update_warning()
|
||||
{
|
||||
global $db, $mybb, $plugins;
|
||||
|
||||
$warning = &$this->data;
|
||||
|
||||
$warning['wid'] = (int)$warning['wid'];
|
||||
if($warning['wid'] <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->write_warning_data = array(
|
||||
"expired" => 1,
|
||||
"daterevoked" => TIME_NOW,
|
||||
"revokedby" => $mybb->user['uid'],
|
||||
"revokereason" => $db->escape_string($warning['reason'])
|
||||
);
|
||||
|
||||
$plugins->run_hooks("datahandler_warnings_update_warning", $this);
|
||||
|
||||
$db->update_query("warnings", $this->write_warning_data, "wid='{$warning['wid']}'");
|
||||
|
||||
$this->update_user('update');
|
||||
|
||||
return $this->write_warning_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
457
webroot/forum/inc/db_base.php
Normal file
457
webroot/forum/inc/db_base.php
Normal file
@@ -0,0 +1,457 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
interface DB_Base
|
||||
{
|
||||
/**
|
||||
* Connect to the database server.
|
||||
*
|
||||
* @param array $config Array of DBMS connection details.
|
||||
* @return resource|PDOStatement|mysqli_result The DB connection resource. Returns false on fail or -1 on a db connect failure.
|
||||
*/
|
||||
function connect($config);
|
||||
|
||||
/**
|
||||
* Query the database.
|
||||
*
|
||||
* @param string $string The query SQL.
|
||||
* @param integer|bool $hide_errors 1 if hide errors, 0 if not.
|
||||
* @param integer 1 $write_query if executes on master database, 0 if not.
|
||||
* @return resource|PDOStatement|mysqli_result The query data.
|
||||
*/
|
||||
function query($string, $hide_errors=0, $write_query=0);
|
||||
|
||||
/**
|
||||
* Execute a write query on the master database
|
||||
*
|
||||
* @param string $query The query SQL.
|
||||
* @param boolean|int $hide_errors 1 if hide errors, 0 if not.
|
||||
* @return resource|PDOStatement|mysqli_result The query data.
|
||||
*/
|
||||
function write_query($query, $hide_errors=0);
|
||||
|
||||
/**
|
||||
* Explain a query on the database.
|
||||
*
|
||||
* @param string $string The query SQL.
|
||||
* @param string $qtime The time it took to perform the query.
|
||||
*/
|
||||
function explain_query($string, $qtime);
|
||||
|
||||
/**
|
||||
* Return a result array for a query.
|
||||
*
|
||||
* @param resource|PDOStatement|mysqli_result $query The query ID.
|
||||
* @param int $resulttype The type of array to return. Specified with the different constants for the type using
|
||||
*
|
||||
* @return array The array of results.
|
||||
*/
|
||||
function fetch_array($query, $resulttype=1);
|
||||
|
||||
/**
|
||||
* Return a specific field from a query.
|
||||
*
|
||||
* @param resource|PDOStatement|mysqli_result $query The query ID.
|
||||
* @param string $field The name of the field to return.
|
||||
* @param int|boolean $row The number of the row to fetch it from.
|
||||
*/
|
||||
function fetch_field($query, $field, $row=false);
|
||||
|
||||
/**
|
||||
* Moves internal row pointer to the next row
|
||||
*
|
||||
* @param resource|PDOStatement|mysqli_result $query The query ID.
|
||||
* @param int $row The pointer to move the row to.
|
||||
*/
|
||||
function data_seek($query, $row);
|
||||
|
||||
/**
|
||||
* Return the number of rows resulting from a query.
|
||||
*
|
||||
* @param resource|PDOStatement|mysqli_result $query The query ID.
|
||||
* @return int The number of rows in the result.
|
||||
*/
|
||||
function num_rows($query);
|
||||
|
||||
/**
|
||||
* Return the last id number of inserted data.
|
||||
*
|
||||
* @return int The id number.
|
||||
*/
|
||||
function insert_id();
|
||||
|
||||
/**
|
||||
* Close the connection with the DBMS.
|
||||
*
|
||||
*/
|
||||
function close();
|
||||
|
||||
/**
|
||||
* Return an error number.
|
||||
*
|
||||
* @return int The error number of the current error.
|
||||
*/
|
||||
function error_number();
|
||||
|
||||
/**
|
||||
* Return an error string.
|
||||
*
|
||||
* @return string The explanation for the current error.
|
||||
*/
|
||||
function error_string();
|
||||
|
||||
/**
|
||||
* Output a database error.
|
||||
*
|
||||
* @param string $string The string to present as an error.
|
||||
*/
|
||||
function error($string="");
|
||||
|
||||
/**
|
||||
* Returns the number of affected rows in a query.
|
||||
*
|
||||
* @return int The number of affected rows.
|
||||
*/
|
||||
function affected_rows();
|
||||
|
||||
/**
|
||||
* Return the number of fields.
|
||||
*
|
||||
* @param resource|PDOStatement|mysqli_result $query The query ID.
|
||||
* @return int The number of fields.
|
||||
*/
|
||||
function num_fields($query);
|
||||
|
||||
/**
|
||||
* Lists all functions in the database.
|
||||
*
|
||||
* @param string $database The database name.
|
||||
* @param string $prefix Prefix of the table (optional)
|
||||
* @return array The table list.
|
||||
*/
|
||||
function list_tables($database, $prefix='');
|
||||
|
||||
/**
|
||||
* Check if a table exists in a database.
|
||||
*
|
||||
* @param string $table The table name.
|
||||
* @return boolean True when exists, false if not.
|
||||
*/
|
||||
function table_exists($table);
|
||||
|
||||
/**
|
||||
* Check if a field exists in a database.
|
||||
*
|
||||
* @param string $field The field name.
|
||||
* @param string $table The table name.
|
||||
* @return boolean True when exists, false if not.
|
||||
*/
|
||||
function field_exists($field, $table);
|
||||
|
||||
/**
|
||||
* Add a shutdown query.
|
||||
*
|
||||
* @param resource|PDOStatement|mysqli_result $query The query data.
|
||||
* @param string $name An optional name for the query.
|
||||
*/
|
||||
function shutdown_query($query, $name='');
|
||||
|
||||
/**
|
||||
* Performs a simple select query.
|
||||
*
|
||||
* @param string $table The table name to be queried.
|
||||
* @param string $fields Comma delimited list of fields to be selected.
|
||||
* @param string $conditions SQL formatted list of conditions to be matched.
|
||||
* @param array $options List of options: group by, order by, order direction, limit, limit start.
|
||||
* @return resource|PDOStatement|mysqli_result The query data.
|
||||
*/
|
||||
function simple_select($table, $fields="*", $conditions="", $options=array());
|
||||
|
||||
/**
|
||||
* Build an insert query from an array.
|
||||
*
|
||||
* @param string $table The table name to perform the query on.
|
||||
* @param array $array An array of fields and their values.
|
||||
* @return int The insert ID if available
|
||||
*/
|
||||
function insert_query($table, $array);
|
||||
|
||||
/**
|
||||
* Build one query for multiple inserts from a multidimensional array.
|
||||
*
|
||||
* @param string $table The table name to perform the query on.
|
||||
* @param array $array An array of inserts.
|
||||
* @return void
|
||||
*/
|
||||
function insert_query_multiple($table, $array);
|
||||
|
||||
/**
|
||||
* Build an update query from an array.
|
||||
*
|
||||
* @param string $table The table name to perform the query on.
|
||||
* @param array $array An array of fields and their values.
|
||||
* @param string $where An optional where clause for the query.
|
||||
* @param string $limit An optional limit clause for the query.
|
||||
* @param boolean $no_quote An option to quote incoming values of the array.
|
||||
* @return resource|PDOStatement|mysqli_result The query data.
|
||||
*/
|
||||
function update_query($table, $array, $where="", $limit="", $no_quote=false);
|
||||
|
||||
/**
|
||||
* Build a delete query.
|
||||
*
|
||||
* @param string $table The table name to perform the query on.
|
||||
* @param string $where An optional where clause for the query.
|
||||
* @param string $limit An optional limit clause for the query.
|
||||
* @return resource|PDOStatement|mysqli_result The query data.
|
||||
*/
|
||||
function delete_query($table, $where="", $limit="");
|
||||
|
||||
/**
|
||||
* Escape a string according to the MySQL escape format.
|
||||
*
|
||||
* @param string $string The string to be escaped.
|
||||
* @return string The escaped string.
|
||||
*/
|
||||
function escape_string($string);
|
||||
|
||||
/**
|
||||
* Frees the resources of a query.
|
||||
*
|
||||
* @param resource|PDOStatement|mysqli_result $query The query to destroy.
|
||||
* @return boolean Returns true on success, false on faliure
|
||||
*/
|
||||
function free_result($query);
|
||||
|
||||
/**
|
||||
* Escape a string used within a like command.
|
||||
*
|
||||
* @param string $string The string to be escaped.
|
||||
* @return string The escaped string.
|
||||
*/
|
||||
function escape_string_like($string);
|
||||
|
||||
/**
|
||||
* Gets the current version of MySQL.
|
||||
*
|
||||
* @return string Version of MySQL.
|
||||
*/
|
||||
function get_version();
|
||||
|
||||
/**
|
||||
* Optimizes a specific table.
|
||||
*
|
||||
* @param string $table The name of the table to be optimized.
|
||||
*/
|
||||
function optimize_table($table);
|
||||
|
||||
/**
|
||||
* Analyzes a specific table.
|
||||
*
|
||||
* @param string $table The name of the table to be analyzed.
|
||||
*/
|
||||
function analyze_table($table);
|
||||
|
||||
/**
|
||||
* Show the "create table" command for a specific table.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
* @return string The SQL command to create the specified table.
|
||||
*/
|
||||
function show_create_table($table);
|
||||
|
||||
/**
|
||||
* Show the "show fields from" command for a specific table.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
* @return array Field info for that table
|
||||
*/
|
||||
function show_fields_from($table);
|
||||
|
||||
/**
|
||||
* Returns whether or not the table contains a fulltext index.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
* @param string $index Optionally specify the name of the index.
|
||||
* @return boolean True or false if the table has a fulltext index or not.
|
||||
*/
|
||||
function is_fulltext($table, $index="");
|
||||
|
||||
/**
|
||||
* Returns whether or not this database engine supports fulltext indexing.
|
||||
*
|
||||
* @param string $table The table to be checked.
|
||||
* @return boolean True or false if supported or not.
|
||||
*/
|
||||
function supports_fulltext($table);
|
||||
|
||||
/**
|
||||
* Checks to see if an index exists on a specified table
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
* @param string $index The name of the index.
|
||||
*/
|
||||
function index_exists($table, $index);
|
||||
|
||||
/**
|
||||
* Returns whether or not this database engine supports boolean fulltext matching.
|
||||
*
|
||||
* @param string $table The table to be checked.
|
||||
* @return boolean True or false if supported or not.
|
||||
*/
|
||||
function supports_fulltext_boolean($table);
|
||||
|
||||
/**
|
||||
* Creates a fulltext index on the specified column in the specified table with optional index name.
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
* @param string $column Name of the column to be indexed.
|
||||
* @param string $name The index name, optional.
|
||||
*/
|
||||
function create_fulltext_index($table, $column, $name="");
|
||||
|
||||
/**
|
||||
* Drop an index with the specified name from the specified table
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
* @param string $name The name of the index.
|
||||
*/
|
||||
function drop_index($table, $name);
|
||||
|
||||
/**
|
||||
* Drop an table with the specified table
|
||||
*
|
||||
* @param string $table The name of the table.
|
||||
* @param boolean $hard Hard drop - no checking
|
||||
* @param boolean $table_prefix Use table prefix?
|
||||
*/
|
||||
function drop_table($table, $hard=false, $table_prefix=true);
|
||||
|
||||
/**
|
||||
* Renames a table
|
||||
*
|
||||
* @param string $old_table The old table name
|
||||
* @param string $new_table the new table name
|
||||
* @param boolean $table_prefix Use table prefix?
|
||||
*/
|
||||
function rename_table($old_table, $new_table, $table_prefix=true);
|
||||
|
||||
/**
|
||||
* Replace contents of table with values
|
||||
*
|
||||
* @param string $table The table
|
||||
* @param array $replacements The replacements
|
||||
* @param string|array $default_field The default field(s)
|
||||
* @param boolean $insert_id Whether or not to return an insert id. True by default
|
||||
*/
|
||||
function replace_query($table, $replacements=array(), $default_field="", $insert_id=true);
|
||||
|
||||
/**
|
||||
* Drops a column
|
||||
*
|
||||
* @param string $table The table
|
||||
* @param string $column The column name
|
||||
*/
|
||||
function drop_column($table, $column);
|
||||
|
||||
/**
|
||||
* Adds a column
|
||||
*
|
||||
* @param string $table The table
|
||||
* @param string $column The column name
|
||||
* @param string $definition The new column definition
|
||||
*/
|
||||
function add_column($table, $column, $definition);
|
||||
|
||||
/**
|
||||
* Modifies a column
|
||||
*
|
||||
* @param string $table The table
|
||||
* @param string $column The column name
|
||||
* @param string $new_definition the new column definition
|
||||
* @param boolean|string $new_not_null Whether to "drop" or "set" the NOT NULL attribute (no change if false)
|
||||
* @param boolean|string $new_default_value The new default value, or false to drop the attribute
|
||||
* @return bool Returns true if all queries are executed successfully or false if one of them failed
|
||||
*/
|
||||
function modify_column($table, $column, $new_definition, $new_not_null=false, $new_default_value=false);
|
||||
|
||||
/**
|
||||
* Renames a column
|
||||
*
|
||||
* @param string $table The table
|
||||
* @param string $old_column The old column name
|
||||
* @param string $new_column the new column name
|
||||
* @param string $new_definition the new column definition
|
||||
* @param boolean|string $new_not_null Whether to "drop" or "set" the NOT NULL attribute (no change if false)
|
||||
* @param boolean|string $new_default_value The new default value, or false to drop the attribute
|
||||
* @return bool Returns true if all queries are executed successfully
|
||||
*/
|
||||
function rename_column($table, $old_column, $new_column, $new_definition, $new_not_null=false, $new_default_value=false);
|
||||
|
||||
/**
|
||||
* Sets the table prefix used by the simple select, insert, update and delete functions
|
||||
*
|
||||
* @param string $prefix The new table prefix
|
||||
*/
|
||||
function set_table_prefix($prefix);
|
||||
|
||||
/**
|
||||
* Fetched the total size of all mysql tables or a specific table
|
||||
*
|
||||
* @param string $table The table (optional)
|
||||
* @return integer the total size of all mysql tables or a specific table
|
||||
*/
|
||||
function fetch_size($table='');
|
||||
|
||||
/**
|
||||
* Fetch a list of database character sets this DBMS supports
|
||||
*
|
||||
* @return array|bool Array of supported character sets with array key being the name, array value being display name. False if unsupported
|
||||
*/
|
||||
function fetch_db_charsets();
|
||||
|
||||
/**
|
||||
* Fetch a database collation for a particular database character set
|
||||
*
|
||||
* @param string $charset The database character set
|
||||
* @return string|bool The matching database collation, false if unsupported
|
||||
*/
|
||||
function fetch_charset_collation($charset);
|
||||
|
||||
/**
|
||||
* Fetch a character set/collation string for use with CREATE TABLE statements. Uses current DB encoding
|
||||
*
|
||||
* @return string The built string, empty if unsupported
|
||||
*/
|
||||
function build_create_table_collation();
|
||||
|
||||
/**
|
||||
* Time how long it takes for a particular piece of code to run. Place calls above & below the block of code.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
function get_execution_time();
|
||||
|
||||
/**
|
||||
* Binary database fields require special attention.
|
||||
*
|
||||
* @param string $string Binary value
|
||||
* @return string Encoded binary value
|
||||
*/
|
||||
function escape_binary($string);
|
||||
|
||||
/**
|
||||
* Unescape binary data.
|
||||
*
|
||||
* @param string $string Binary value
|
||||
* @return string Encoded binary value
|
||||
*/
|
||||
function unescape_binary($string);
|
||||
}
|
||||
1653
webroot/forum/inc/db_mysql.php
Normal file
1653
webroot/forum/inc/db_mysql.php
Normal file
File diff suppressed because it is too large
Load Diff
1634
webroot/forum/inc/db_mysqli.php
Normal file
1634
webroot/forum/inc/db_mysqli.php
Normal file
File diff suppressed because it is too large
Load Diff
234
webroot/forum/inc/db_pdo.php
Normal file
234
webroot/forum/inc/db_pdo.php
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
class dbpdoEngine {
|
||||
|
||||
/**
|
||||
* The database class to store PDO objects
|
||||
*
|
||||
* @var PDO
|
||||
*/
|
||||
public $db;
|
||||
|
||||
/**
|
||||
* The last query resource that ran
|
||||
*
|
||||
* @var PDOStatement
|
||||
*/
|
||||
public $last_query = "";
|
||||
|
||||
public $seek_array = array();
|
||||
|
||||
public $queries = 0;
|
||||
|
||||
/**
|
||||
* Connect to the database.
|
||||
*
|
||||
* @param string $dsn The database DSN.
|
||||
* @param string $username The database username. (depends on DSN)
|
||||
* @param string $password The database user's password. (depends on DSN)
|
||||
* @param array $driver_options The databases driver options (optional)
|
||||
*/
|
||||
function __construct($dsn, $username="", $password="", $driver_options=array())
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->db = new PDO($dsn, $username, $password, $driver_options);
|
||||
}
|
||||
catch(PDOException $exception)
|
||||
{
|
||||
die('Connection failed: '.$exception->getMessage());
|
||||
}
|
||||
|
||||
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the database.
|
||||
*
|
||||
* @param string $string The query SQL.
|
||||
* @return PDOStatement The query data.
|
||||
*/
|
||||
function query($string)
|
||||
{
|
||||
++$this->queries;
|
||||
|
||||
$query = $this->db->query($string, PDO::FETCH_BOTH);
|
||||
$this->last_query = $query;
|
||||
|
||||
$query->guid = $this->queries;
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a result array for a query.
|
||||
*
|
||||
* @param PDOStatement $query The query resource.
|
||||
* @param int $resulttype One of PDO's constants: FETCH_ASSOC, FETCH_BOUND, FETCH_CLASS, FETCH_INTO, FETCH_LAZY, FETCH_NAMED, FETCH_NUM, FETCH_OBJ or FETCH_BOTH
|
||||
* @return array The array of results.
|
||||
*/
|
||||
function fetch_array($query, $resulttype=PDO::FETCH_BOTH)
|
||||
{
|
||||
switch($resulttype)
|
||||
{
|
||||
case PDO::FETCH_ASSOC:
|
||||
case PDO::FETCH_BOUND:
|
||||
case PDO::FETCH_CLASS:
|
||||
case PDO::FETCH_INTO:
|
||||
case PDO::FETCH_LAZY:
|
||||
case PDO::FETCH_NAMED:
|
||||
case PDO::FETCH_NUM:
|
||||
case PDO::FETCH_OBJ:
|
||||
break;
|
||||
default:
|
||||
$resulttype = PDO::FETCH_BOTH;
|
||||
break;
|
||||
}
|
||||
|
||||
if($this->seek_array[$query->guid])
|
||||
{
|
||||
$array = $query->fetch($resulttype, $this->seek_array[$query->guid]['offset'], $this->seek_array[$query->guid]['row']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$array = $query->fetch($resulttype);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves internal row pointer to the next row
|
||||
*
|
||||
* @param PDOStatement $query The query resource.
|
||||
* @param int $row The pointer to move the row to.
|
||||
*/
|
||||
function seek($query, $row)
|
||||
{
|
||||
$this->seek_array[$query->guid] = array('offset' => PDO::FETCH_ORI_ABS, 'row' => $row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of rows resulting from a query.
|
||||
*
|
||||
* @param PDOStatement $query The query resource.
|
||||
* @return int The number of rows in the result.
|
||||
*/
|
||||
function num_rows($query)
|
||||
{
|
||||
if(stripos($query->queryString, 'SELECT') !== false)
|
||||
{
|
||||
$query = $this->db->query($query->queryString);
|
||||
$result = $query->fetchAll();
|
||||
return count($result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $query->rowCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last id number of inserted data.
|
||||
*
|
||||
* @param string $name The name of the insert id to check. (Optional)
|
||||
* @return int The id number.
|
||||
*/
|
||||
function insert_id($name="")
|
||||
{
|
||||
return $this->db->lastInsertId($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error number.
|
||||
*
|
||||
* @param PDOStatement $query The query resource.
|
||||
* @return int The error number of the current error.
|
||||
*/
|
||||
function error_number($query)
|
||||
{
|
||||
if(!method_exists($query, "errorCode"))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
$errorcode = $query->errorCode();
|
||||
|
||||
return $errorcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error string.
|
||||
*
|
||||
* @param PDOStatement $query The query resource.
|
||||
* @return array The error string of the current error.
|
||||
*/
|
||||
function error_string($query)
|
||||
{
|
||||
if(!method_exists($query, "errorInfo"))
|
||||
{
|
||||
return $this->db->errorInfo();
|
||||
}
|
||||
return $query->errorInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of affected rows in a query.
|
||||
*
|
||||
* @param PDOStatement $query
|
||||
* @return int The number of affected rows.
|
||||
*/
|
||||
function affected_rows($query)
|
||||
{
|
||||
return $query->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of fields.
|
||||
*
|
||||
* @param PDOStatement $query The query resource.
|
||||
* @return int The number of fields.
|
||||
*/
|
||||
function num_fields($query)
|
||||
{
|
||||
return $query->columnCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string according to the pdo escape format.
|
||||
*
|
||||
* @param string $string The string to be escaped.
|
||||
* @return string The escaped string.
|
||||
*/
|
||||
function escape_string($string)
|
||||
{
|
||||
$string = $this->db->quote($string);
|
||||
|
||||
// Remove ' from the begginging of the string and at the end of the string, because we already use it in insert_query
|
||||
$string = substr($string, 1);
|
||||
$string = substr($string, 0, -1);
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a selected attribute
|
||||
*
|
||||
* @param string $attribute The attribute to check.
|
||||
* @return string The value of the attribute.
|
||||
*/
|
||||
function get_attribute($attribute)
|
||||
{
|
||||
$attribute = $this->db->getAttribute(constant("PDO::".$attribute.""));
|
||||
|
||||
return $attribute;
|
||||
}
|
||||
}
|
||||
1585
webroot/forum/inc/db_pgsql.php
Normal file
1585
webroot/forum/inc/db_pgsql.php
Normal file
File diff suppressed because it is too large
Load Diff
1565
webroot/forum/inc/db_sqlite.php
Normal file
1565
webroot/forum/inc/db_sqlite.php
Normal file
File diff suppressed because it is too large
Load Diff
8979
webroot/forum/inc/functions.php
Normal file
8979
webroot/forum/inc/functions.php
Normal file
File diff suppressed because it is too large
Load Diff
269
webroot/forum/inc/functions_archive.php
Normal file
269
webroot/forum/inc/functions_archive.php
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Output the archive page header.
|
||||
*
|
||||
* @param string $title The page title.
|
||||
* @param string $fulltitle The full page title.
|
||||
* @param string $fullurl The full page URL.
|
||||
*/
|
||||
function archive_header($title="", $fulltitle="", $fullurl="")
|
||||
{
|
||||
global $mybb, $lang, $db, $nav, $archiveurl, $sent_header;
|
||||
|
||||
// Build the archive navigation.
|
||||
$nav = archive_navigation();
|
||||
|
||||
// If there is a title, append it to the bbname.
|
||||
if(!$title)
|
||||
{
|
||||
$title = $mybb->settings['bbname'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = $mybb->settings['bbname']." - ".$title;
|
||||
}
|
||||
|
||||
// If the language doesn't have a charset, make it UTF-8.
|
||||
if($lang->settings['charset'])
|
||||
{
|
||||
$charset = $lang->settings['charset'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$charset = "utf-8";
|
||||
}
|
||||
|
||||
$dir = '';
|
||||
if($lang->settings['rtl'] == 1)
|
||||
{
|
||||
$dir = " dir=\"rtl\"";
|
||||
}
|
||||
|
||||
if($lang->settings['htmllang'])
|
||||
{
|
||||
$htmllang = " xml:lang=\"".$lang->settings['htmllang']."\" lang=\"".$lang->settings['htmllang']."\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
$htmllang = " xml:lang=\"en\" lang=\"en\"";
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"<?php echo $dir; echo $htmllang; ?>>
|
||||
<head>
|
||||
<title><?php echo $title; ?></title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=<?php echo $charset; ?>" />
|
||||
<meta name="robots" content="index,follow" />
|
||||
<link type="text/css" rel="stylesheet" rev="stylesheet" href="<?php echo $archiveurl; ?>/screen.css" media="screen" />
|
||||
<link type="text/css" rel="stylesheet" rev="stylesheet" href="<?php echo $archiveurl; ?>/print.css" media="print" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<h1><a href="<?php echo $mybb->settings['bburl']; ?>/index.php"><?php echo $mybb->settings['bbname_orig']; ?></a></h1>
|
||||
<div class="navigation"><?php echo $nav; ?></div>
|
||||
<div id="fullversion"><strong><?php echo $lang->archive_fullversion; ?></strong> <a href="<?php echo $fullurl; ?>"><?php echo $fulltitle; ?></a></div>
|
||||
<div id="infobox"><?php echo $lang->sprintf($lang->archive_note, $fullurl); ?></div>
|
||||
<div id="content">
|
||||
<?php
|
||||
$sent_header = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the archive navigation.
|
||||
*
|
||||
* @return string The build navigation
|
||||
*/
|
||||
function archive_navigation()
|
||||
{
|
||||
global $navbits, $mybb, $lang;
|
||||
|
||||
$navsep = " > ";
|
||||
$nav = $activesep = '';
|
||||
if(is_array($navbits))
|
||||
{
|
||||
reset($navbits);
|
||||
foreach($navbits as $key => $navbit)
|
||||
{
|
||||
if(!empty($navbits[$key+1]))
|
||||
{
|
||||
if(!empty($navbits[$key+2]))
|
||||
{
|
||||
$sep = $navsep;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sep = "";
|
||||
}
|
||||
$nav .= "<a href=\"".$navbit['url']."\">".$navbit['name']."</a>$sep";
|
||||
}
|
||||
}
|
||||
$navsize = count($navbits);
|
||||
$navbit = $navbits[$navsize-1];
|
||||
}
|
||||
if(!empty($nav))
|
||||
{
|
||||
$activesep = $navsep;
|
||||
}
|
||||
$nav .= $activesep.$navbit['name'];
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output multipage navigation.
|
||||
*
|
||||
* @param int $count The total number of items.
|
||||
* @param int $perpage The items per page.
|
||||
* @param int $page The current page.
|
||||
* @param string $url The URL base.
|
||||
*/
|
||||
function archive_multipage($count, $perpage, $page, $url)
|
||||
{
|
||||
global $lang;
|
||||
if($count > $perpage)
|
||||
{
|
||||
$pages = $count / $perpage;
|
||||
$pages = ceil($pages);
|
||||
|
||||
$mppage = null;
|
||||
for($i = 1; $i <= $pages; ++$i)
|
||||
{
|
||||
if($i == $page)
|
||||
{
|
||||
$mppage .= "<strong>$i</strong> ";
|
||||
}
|
||||
else
|
||||
{
|
||||
$mppage .= "<a href=\"$url-$i.html\">$i</a> ";
|
||||
}
|
||||
}
|
||||
$multipage = "<div class=\"multipage\"><strong>".$lang->archive_pages."</strong> $mppage</div>";
|
||||
echo $multipage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the archive footer.
|
||||
*
|
||||
*/
|
||||
function archive_footer()
|
||||
{
|
||||
global $mybb, $lang, $db, $nav, $maintimer, $fulltitle, $fullurl, $sent_header;
|
||||
$totaltime = $maintimer->stop();
|
||||
if($mybb->settings['showvernum'] == 1)
|
||||
{
|
||||
$mybbversion = ' '.$mybb->version;
|
||||
}
|
||||
else
|
||||
{
|
||||
$mybbversion = "";
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="navigation"><?php echo $nav; ?></div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<?php echo $lang->powered_by; ?> <a href="https://mybb.com">MyBB</a><?php echo $mybbversion; ?>, © 2002-<?php echo date("Y"); ?> <a href="https://mybb.com">MyBB Group</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Output an archive error.
|
||||
*
|
||||
* @param string $error The error language string identifier.
|
||||
*/
|
||||
function archive_error($error)
|
||||
{
|
||||
global $lang, $mybb, $sent_header;
|
||||
if(!$sent_header)
|
||||
{
|
||||
archive_header("", $mybb->settings['bbname'], $mybb->settings['bburl']."/index.php");
|
||||
}
|
||||
?>
|
||||
<div class="error">
|
||||
<div class="header"><?php echo $lang->error; ?></div>
|
||||
<div class="message"><?php echo $error; ?></div>
|
||||
</div>
|
||||
<?php
|
||||
archive_footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ouput a "no permission"page.
|
||||
*/
|
||||
function archive_error_no_permission()
|
||||
{
|
||||
global $lang, $db, $session;
|
||||
|
||||
$noperm_array = array (
|
||||
"nopermission" => '1',
|
||||
"location1" => 0,
|
||||
"location2" => 0
|
||||
);
|
||||
|
||||
$db->update_query("sessions", $noperm_array, "sid='{$session->sid}'");
|
||||
|
||||
archive_error($lang->archive_nopermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the password given on a certain forum for validity
|
||||
*
|
||||
* @param int $fid The forum ID
|
||||
* @param int $pid The Parent ID
|
||||
* @return bool Returns false on failure
|
||||
*/
|
||||
function check_forum_password_archive($fid, $pid=0)
|
||||
{
|
||||
global $forum_cache, $mybb;
|
||||
|
||||
if(!is_array($forum_cache))
|
||||
{
|
||||
$forum_cache = cache_forums();
|
||||
if(!$forum_cache)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through each of parent forums to ensure we have a password for them too
|
||||
$parents = explode(',', $forum_cache[$fid]['parentlist']);
|
||||
rsort($parents);
|
||||
if(!empty($parents))
|
||||
{
|
||||
foreach($parents as $parent_id)
|
||||
{
|
||||
if($parent_id == $fid || $parent_id == $pid)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if($forum_cache[$parent_id]['password'] != "")
|
||||
{
|
||||
check_forum_password_archive($parent_id, $fid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$password = $forum_cache[$fid]['password'];
|
||||
if($password)
|
||||
{
|
||||
if(!isset($mybb->cookies['forumpass'][$fid]) || !my_hash_equals(md5($mybb->user['uid'].$password), $mybb->cookies['forumpass'][$fid]))
|
||||
{
|
||||
archive_error_no_permission();
|
||||
}
|
||||
}
|
||||
}
|
||||
1100
webroot/forum/inc/functions_calendar.php
Normal file
1100
webroot/forum/inc/functions_calendar.php
Normal file
File diff suppressed because it is too large
Load Diff
602
webroot/forum/inc/functions_forumlist.php
Normal file
602
webroot/forum/inc/functions_forumlist.php
Normal file
@@ -0,0 +1,602 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Build a list of forum bits.
|
||||
*
|
||||
* @param int $pid The parent forum to fetch the child forums for (0 assumes all)
|
||||
* @param int $depth The depth to return forums with.
|
||||
* @return array Array of information regarding the child forums of this parent forum
|
||||
*/
|
||||
function build_forumbits($pid=0, $depth=1)
|
||||
{
|
||||
global $db, $fcache, $moderatorcache, $forumpermissions, $theme, $mybb, $templates, $bgcolor, $collapsed, $lang, $showdepth, $plugins, $parser, $forum_viewers;
|
||||
static $private_forums;
|
||||
|
||||
$forum_listing = '';
|
||||
|
||||
// If no forums exist with this parent, do nothing
|
||||
if(empty($fcache[$pid]) || !is_array($fcache[$pid]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$parent_counters['threads'] = 0;
|
||||
$parent_counters['posts'] = 0;
|
||||
$parent_counters['unapprovedposts'] = 0;
|
||||
$parent_counters['unapprovedthreads'] = 0;
|
||||
$parent_counters['viewers'] = 0;
|
||||
$forum_list = $comma = '';
|
||||
$donecount = 0;
|
||||
|
||||
// Foreach of the forums in this parent
|
||||
foreach($fcache[$pid] as $parent)
|
||||
{
|
||||
foreach($parent as $forum)
|
||||
{
|
||||
$subforums = $sub_forums = '';
|
||||
$lastpost_data = array(
|
||||
'lastpost' => 0
|
||||
);
|
||||
$forum_viewers_text = '';
|
||||
$forum_viewers_text_plain = '';
|
||||
|
||||
// Get the permissions for this forum
|
||||
$permissions = $forumpermissions[$forum['fid']];
|
||||
|
||||
// If this user doesnt have permission to view this forum and we're hiding private forums, skip this forum
|
||||
if($permissions['canview'] != 1 && $mybb->settings['hideprivateforums'] == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$forum = $plugins->run_hooks("build_forumbits_forum", $forum);
|
||||
|
||||
// Build the link to this forum
|
||||
$forum_url = get_forum_link($forum['fid']);
|
||||
|
||||
// This forum has a password, and the user isn't authenticated with it - hide post information
|
||||
$hideinfo = $hidecounters = false;
|
||||
$hidelastpostinfo = false;
|
||||
$showlockicon = 0;
|
||||
if(isset($permissions['canviewthreads']) && $permissions['canviewthreads'] != 1)
|
||||
{
|
||||
$hideinfo = true;
|
||||
}
|
||||
|
||||
if(isset($permissions['canonlyviewownthreads']) && $permissions['canonlyviewownthreads'] == 1)
|
||||
{
|
||||
$hidecounters = true;
|
||||
|
||||
// If we only see our own threads, find out if there's a new post in one of them so the lightbulb shows
|
||||
if(!is_array($private_forums))
|
||||
{
|
||||
$private_forums = $fids = array();
|
||||
foreach($fcache as $fcache_p)
|
||||
{
|
||||
foreach($fcache_p as $parent_p)
|
||||
{
|
||||
foreach($parent_p as $forum_p)
|
||||
{
|
||||
if($forumpermissions[$forum_p['fid']]['canonlyviewownthreads'])
|
||||
{
|
||||
$fids[] = $forum_p['fid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($fids))
|
||||
{
|
||||
$fids = implode(',', $fids);
|
||||
$query = $db->simple_select("threads", "tid, fid, subject, lastpost, lastposter, lastposteruid", "uid = '{$mybb->user['uid']}' AND fid IN ({$fids}) AND visible != '-2'", array("order_by" => "lastpost", "order_dir" => "desc"));
|
||||
|
||||
while($thread = $db->fetch_array($query))
|
||||
{
|
||||
if(!$private_forums[$thread['fid']])
|
||||
{
|
||||
$private_forums[$thread['fid']] = $thread;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($private_forums[$forum['fid']]['lastpost'])
|
||||
{
|
||||
$forum['lastpost'] = $private_forums[$forum['fid']]['lastpost'];
|
||||
|
||||
if(!$private_forums[$forum['fid']]['lastposteruid'] && !$private_forums[$forum['fid']]['lastposter'])
|
||||
{
|
||||
$private_forums[$forum['fid']]['lastposter'] = $lang->guest; // htmlspecialchars_uni'd when formatted later
|
||||
}
|
||||
|
||||
$lastpost_data = array(
|
||||
"lastpost" => $private_forums[$forum['fid']]['lastpost'],
|
||||
"lastpostsubject" => $private_forums[$forum['fid']]['subject'],
|
||||
"lastposter" => $private_forums[$forum['fid']]['lastposter'],
|
||||
"lastposttid" => $private_forums[$forum['fid']]['tid'],
|
||||
"lastposteruid" => $private_forums[$forum['fid']]['lastposteruid']
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$forum['lastposteruid'] && !$forum['lastposter'])
|
||||
{
|
||||
$forum['lastposter'] = $lang->guest; // htmlspecialchars_uni'd when formatted later
|
||||
}
|
||||
|
||||
$lastpost_data = array(
|
||||
"lastpost" => $forum['lastpost'],
|
||||
"lastpostsubject" => $forum['lastpostsubject'],
|
||||
"lastposter" => $forum['lastposter'],
|
||||
"lastposttid" => $forum['lastposttid'],
|
||||
"lastposteruid" => $forum['lastposteruid']
|
||||
);
|
||||
}
|
||||
|
||||
if($forum['password'])
|
||||
{
|
||||
if(!isset($mybb->cookies['forumpass'][$forum['fid']]) || !my_hash_equals($mybb->cookies['forumpass'][$forum['fid']], md5($mybb->user['uid'].$forum['password'])))
|
||||
{
|
||||
$hideinfo = true;
|
||||
$showlockicon = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch subforums of this forum
|
||||
if(isset($fcache[$forum['fid']]))
|
||||
{
|
||||
$forum_info = build_forumbits($forum['fid'], $depth+1);
|
||||
|
||||
// Increment forum counters with counters from child forums
|
||||
$forum['threads'] += $forum_info['counters']['threads'];
|
||||
$forum['posts'] += $forum_info['counters']['posts'];
|
||||
$forum['unapprovedthreads'] += $forum_info['counters']['unapprovedthreads'];
|
||||
$forum['unapprovedposts'] += $forum_info['counters']['unapprovedposts'];
|
||||
|
||||
if(!empty($forum_info['counters']['viewing']))
|
||||
{
|
||||
$forum['viewers'] += $forum_info['counters']['viewing'];
|
||||
}
|
||||
|
||||
// If the child forums' lastpost is greater than the one for this forum, set it as the child forums greatest.
|
||||
if($forum_info['lastpost']['lastpost'] > $lastpost_data['lastpost'])
|
||||
{
|
||||
$lastpost_data = $forum_info['lastpost'];
|
||||
|
||||
/*
|
||||
// If our subforum is unread, then so must be our parents. Force our parents to unread as well
|
||||
if(strstr($forum_info['lightbulb']['folder'], "on") !== false)
|
||||
{
|
||||
$forum['lastread'] = 0;
|
||||
}
|
||||
// Otherwise, if we have an explicit record in the db, we must make sure that it is explicitly set
|
||||
else
|
||||
{
|
||||
$lastpost_data['lastpost'] = $forum['lastpost'];
|
||||
}*/
|
||||
}
|
||||
|
||||
$sub_forums = $forum_info['forum_list'];
|
||||
}
|
||||
|
||||
// If we are hiding information (lastpost) because we aren't authenticated against the password for this forum, remove them
|
||||
if($hidelastpostinfo == true)
|
||||
{
|
||||
$lastpost_data = array(
|
||||
'lastpost' => 0,
|
||||
'lastposter' => ''
|
||||
);
|
||||
}
|
||||
|
||||
// If the current forums lastpost is greater than other child forums of the current parent and forum info isn't hidden, overwrite it
|
||||
if((!isset($parent_lastpost) || $lastpost_data['lastpost'] > $parent_lastpost['lastpost']) && $hideinfo != true)
|
||||
{
|
||||
$parent_lastpost = $lastpost_data;
|
||||
}
|
||||
|
||||
if(is_array($forum_viewers) && isset($forum_viewers[$forum['fid']]) && $forum_viewers[$forum['fid']] > 0)
|
||||
{
|
||||
$forum['viewers'] = $forum_viewers[$forum['fid']];
|
||||
}
|
||||
|
||||
// Increment the counters for the parent forum (returned later)
|
||||
if($hideinfo != true && $hidecounters != true)
|
||||
{
|
||||
$parent_counters['threads'] += $forum['threads'];
|
||||
$parent_counters['posts'] += $forum['posts'];
|
||||
$parent_counters['unapprovedposts'] += $forum['unapprovedposts'];
|
||||
$parent_counters['unapprovedthreads'] += $forum['unapprovedthreads'];
|
||||
|
||||
if(!empty($forum['viewers']))
|
||||
{
|
||||
$parent_counters['viewers'] += $forum['viewers'];
|
||||
}
|
||||
}
|
||||
|
||||
// Done with our math, lets talk about displaying - only display forums which are under a certain depth
|
||||
if($depth > $showdepth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the lightbulb status indicator for this forum based on the lastpost
|
||||
$lightbulb = get_forum_lightbulb($forum, $lastpost_data, $showlockicon);
|
||||
|
||||
// Fetch the number of unapproved threads and posts for this forum
|
||||
$unapproved = get_forum_unapproved($forum);
|
||||
|
||||
if($hideinfo == true)
|
||||
{
|
||||
unset($unapproved);
|
||||
}
|
||||
|
||||
// Sanitize name and description of forum.
|
||||
$forum['name'] = preg_replace("#&(?!\#[0-9]+;)#si", "&", $forum['name']); // Fix & but allow unicode
|
||||
$forum['description'] = preg_replace("#&(?!\#[0-9]+;)#si", "&", $forum['description']); // Fix & but allow unicode
|
||||
$forum['name'] = preg_replace("#&([^\#])(?![a-z1-4]{1,10};)#i", "&$1", $forum['name']);
|
||||
$forum['description'] = preg_replace("#&([^\#])(?![a-z1-4]{1,10};)#i", "&$1", $forum['description']);
|
||||
|
||||
// If this is a forum and we've got subforums of it, load the subforums list template
|
||||
if($depth == 2 && $sub_forums)
|
||||
{
|
||||
eval("\$subforums = \"".$templates->get("forumbit_subforums")."\";");
|
||||
}
|
||||
// A depth of three indicates a comma separated list of forums within a forum
|
||||
else if($depth == 3)
|
||||
{
|
||||
if($donecount < $mybb->settings['subforumsindex'])
|
||||
{
|
||||
$statusicon = '';
|
||||
|
||||
// Showing mini status icons for this forum
|
||||
if($mybb->settings['subforumsstatusicons'] == 1)
|
||||
{
|
||||
$lightbulb['folder'] = "mini".$lightbulb['folder'];
|
||||
eval("\$statusicon = \"".$templates->get("forumbit_depth3_statusicon", 1, 0)."\";");
|
||||
}
|
||||
|
||||
// Fetch the template and append it to the list
|
||||
eval("\$forum_list .= \"".$templates->get("forumbit_depth3", 1, 0)."\";");
|
||||
$comma = $lang->comma;
|
||||
}
|
||||
|
||||
// Have we reached our max visible subforums? put a nice message and break out of the loop
|
||||
++$donecount;
|
||||
if($donecount == $mybb->settings['subforumsindex'])
|
||||
{
|
||||
if(subforums_count($fcache[$pid]) > $donecount)
|
||||
{
|
||||
$forum_list .= $comma.$lang->sprintf($lang->more_subforums, (subforums_count($fcache[$pid]) - $donecount));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Forum is a category, set template type
|
||||
if($forum['type'] == 'c')
|
||||
{
|
||||
$forumcat = '_cat';
|
||||
}
|
||||
// Forum is a standard forum, set template type
|
||||
else
|
||||
{
|
||||
$forumcat = '_forum';
|
||||
}
|
||||
|
||||
if($forum['linkto'] == '')
|
||||
{
|
||||
// No posts have been made in this forum - show never text
|
||||
if($lastpost_data['lastpost'] == 0 && $hideinfo != true)
|
||||
{
|
||||
eval("\$lastpost = \"".$templates->get("forumbit_depth2_forum_lastpost_never")."\";");
|
||||
}
|
||||
elseif($hideinfo != true)
|
||||
{
|
||||
// Format lastpost date and time
|
||||
$lastpost_date = my_date('relative', $lastpost_data['lastpost']);
|
||||
|
||||
// Set up the last poster, last post thread id, last post subject and format appropriately
|
||||
$lastpost_data['lastposter'] = htmlspecialchars_uni($lastpost_data['lastposter']);
|
||||
$lastpost_profilelink = build_profile_link($lastpost_data['lastposter'], $lastpost_data['lastposteruid']);
|
||||
$lastpost_link = get_thread_link($lastpost_data['lastposttid'], 0, "lastpost");
|
||||
$lastpost_subject = $full_lastpost_subject = $parser->parse_badwords($lastpost_data['lastpostsubject']);
|
||||
if(my_strlen($lastpost_subject) > 25)
|
||||
{
|
||||
$lastpost_subject = my_substr($lastpost_subject, 0, 25)."...";
|
||||
}
|
||||
$lastpost_subject = htmlspecialchars_uni($lastpost_subject);
|
||||
$full_lastpost_subject = htmlspecialchars_uni($full_lastpost_subject);
|
||||
|
||||
// Call lastpost template
|
||||
if($depth != 1)
|
||||
{
|
||||
eval("\$lastpost = \"".$templates->get("forumbit_depth{$depth}_forum_lastpost")."\";");
|
||||
}
|
||||
}
|
||||
|
||||
if($mybb->settings['showforumviewing'] != 0 && $forum['viewers'] > 0)
|
||||
{
|
||||
if($forum['viewers'] == 1)
|
||||
{
|
||||
$forum_viewers_text = $lang->viewing_one;
|
||||
}
|
||||
else
|
||||
{
|
||||
$forum_viewers_text = $lang->sprintf($lang->viewing_multiple, $forum['viewers']);
|
||||
}
|
||||
$forum_viewers_text_plain = $forum_viewers_text;
|
||||
eval("\$forum_viewers_text = \"".$templates->get("forumbit_depth2_forum_viewers")."\";");
|
||||
}
|
||||
}
|
||||
// If this forum is a link or is password protected and the user isn't authenticated, set counters to "-"
|
||||
if($forum['linkto'] != '' || $hideinfo == true || $hidecounters == true)
|
||||
{
|
||||
$posts = "-";
|
||||
$threads = "-";
|
||||
}
|
||||
// Otherwise, format thread and post counts
|
||||
else
|
||||
{
|
||||
$posts = my_number_format($forum['posts']);
|
||||
$threads = my_number_format($forum['threads']);
|
||||
}
|
||||
|
||||
// If this forum is a link or is password protected and the user isn't authenticated, set lastpost to "-"
|
||||
if($forum['linkto'] != '' || $hideinfo == true || $hidelastpostinfo == true)
|
||||
{
|
||||
eval("\$lastpost = \"".$templates->get("forumbit_depth2_forum_lastpost_hidden")."\";");
|
||||
}
|
||||
|
||||
// Moderator column is not off
|
||||
if($mybb->settings['modlist'] != 0)
|
||||
{
|
||||
$done_moderators = array(
|
||||
"users" => array(),
|
||||
"groups" => array()
|
||||
);
|
||||
$moderators = '';
|
||||
// Fetch list of moderators from this forum and its parents
|
||||
$parentlistexploded = explode(',', $forum['parentlist']);
|
||||
foreach($parentlistexploded as $mfid)
|
||||
{
|
||||
// This forum has moderators
|
||||
if(isset($moderatorcache[$mfid]) && is_array($moderatorcache[$mfid]))
|
||||
{
|
||||
// Fetch each moderator from the cache and format it, appending it to the list
|
||||
foreach($moderatorcache[$mfid] as $modtype)
|
||||
{
|
||||
foreach($modtype as $moderator)
|
||||
{
|
||||
if($moderator['isgroup'])
|
||||
{
|
||||
if(in_array($moderator['id'], $done_moderators['groups']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$moderator['title'] = htmlspecialchars_uni($moderator['title']);
|
||||
|
||||
eval("\$moderators .= \"".$templates->get("forumbit_moderators_group", 1, 0)."\";");
|
||||
$done_moderators['groups'][] = $moderator['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(in_array($moderator['id'], $done_moderators['users']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$moderator['profilelink'] = get_profile_link($moderator['id']);
|
||||
$moderator['username'] = htmlspecialchars_uni($moderator['username']);
|
||||
|
||||
eval("\$moderators .= \"".$templates->get("forumbit_moderators_user", 1, 0)."\";");
|
||||
$done_moderators['users'][] = $moderator['id'];
|
||||
}
|
||||
$comma = $lang->comma;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$comma = '';
|
||||
|
||||
// If we have a moderators list, load the template
|
||||
if($moderators)
|
||||
{
|
||||
eval("\$modlist = \"".$templates->get("forumbit_moderators")."\";");
|
||||
}
|
||||
else
|
||||
{
|
||||
$modlist = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Descriptions aren't being shown - blank them
|
||||
if($mybb->settings['showdescriptions'] == 0)
|
||||
{
|
||||
$forum['description'] = '';
|
||||
}
|
||||
|
||||
// Check if this category is either expanded or collapsed and hide it as necessary.
|
||||
$expdisplay = '';
|
||||
$collapsed_name = "cat_{$forum['fid']}_c";
|
||||
if(isset($collapsed[$collapsed_name]) && $collapsed[$collapsed_name] == "display: show;")
|
||||
{
|
||||
$expcolimage = "collapse_collapsed.png";
|
||||
$expdisplay = "display: none;";
|
||||
$expthead = " thead_collapsed";
|
||||
$expaltext = "[+]";
|
||||
}
|
||||
else
|
||||
{
|
||||
$expcolimage = "collapse.png";
|
||||
$expthead = "";
|
||||
$expaltext = "[-]";
|
||||
}
|
||||
|
||||
// Swap over the alternate backgrounds
|
||||
$bgcolor = alt_trow();
|
||||
|
||||
// Add the forum to the list
|
||||
eval("\$forum_list .= \"".$templates->get("forumbit_depth$depth$forumcat")."\";");
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($parent_lastpost))
|
||||
{
|
||||
$parent_lastpost = 0;
|
||||
}
|
||||
|
||||
if(!isset($lightbulb))
|
||||
{
|
||||
$lightbulb = '';
|
||||
}
|
||||
|
||||
// Return an array of information to the parent forum including child forums list, counters and lastpost information
|
||||
return array(
|
||||
"forum_list" => $forum_list,
|
||||
"counters" => $parent_counters,
|
||||
"lastpost" => $parent_lastpost,
|
||||
"lightbulb" => $lightbulb,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the status indicator for a forum based on its last post and the read date
|
||||
*
|
||||
* @param array $forum Array of information about the forum
|
||||
* @param array $lastpost Array of information about the lastpost date
|
||||
* @param int $locked Whether or not this forum is locked or not
|
||||
* @return array Array of the folder image to be shown and the alt text
|
||||
*/
|
||||
function get_forum_lightbulb($forum, $lastpost, $locked=0)
|
||||
{
|
||||
global $mybb, $lang, $db, $unread_forums;
|
||||
|
||||
// This forum is a redirect, so override the folder icon with the "offlink" icon.
|
||||
if($forum['linkto'] != '')
|
||||
{
|
||||
$folder = "offlink";
|
||||
$altonoff = $lang->forum_redirect;
|
||||
}
|
||||
// This forum is closed, so override the folder icon with the "offclose" icon.
|
||||
elseif($forum['open'] == 0 || $locked)
|
||||
{
|
||||
$folder = "offclose";
|
||||
$altonoff = $lang->forum_closed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fetch the last read date for this forum
|
||||
if(!empty($forum['lastread']))
|
||||
{
|
||||
$forum_read = $forum['lastread'];
|
||||
}
|
||||
elseif(!empty($mybb->cookies['mybb']['readallforums']))
|
||||
{
|
||||
// We've hit the read all forums as a guest, so use the lastvisit of the user
|
||||
$forum_read = $mybb->cookies['mybb']['lastvisit'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$forum_read = 0;
|
||||
$threadcut = TIME_NOW - 60*60*24*$mybb->settings['threadreadcut'];
|
||||
|
||||
// If the user is a guest, do they have a forumsread cookie?
|
||||
if(!$mybb->user['uid'] && isset($mybb->cookies['mybb']['forumread']))
|
||||
{
|
||||
// If they've visited us before, then they'll have this cookie - otherwise everything is unread...
|
||||
$forum_read = my_get_array_cookie("forumread", $forum['fid']);
|
||||
}
|
||||
else if($mybb->user['uid'] && $mybb->settings['threadreadcut'] > 0 && $threadcut > $lastpost['lastpost'])
|
||||
{
|
||||
// We have a user, the forum's unread and we're over our threadreadcut limit for the lastpost - we mark these as read
|
||||
$forum_read = $lastpost['lastpost'] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//if(!$forum_read)
|
||||
//{
|
||||
//$forum_read = $mybb->user['lastvisit'];
|
||||
//}
|
||||
|
||||
// If the lastpost is greater than the last visit and is greater than the forum read date, we have a new post
|
||||
if($lastpost['lastpost'] > $forum_read && $lastpost['lastpost'] != 0)
|
||||
{
|
||||
$unread_forums++;
|
||||
$folder = "on";
|
||||
$altonoff = $lang->new_posts;
|
||||
}
|
||||
// Otherwise, no new posts
|
||||
else
|
||||
{
|
||||
$folder = "off";
|
||||
$altonoff = $lang->no_new_posts;
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
"folder" => $folder,
|
||||
"altonoff" => $altonoff
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the number of unapproved posts, formatted, from a forum
|
||||
*
|
||||
* @param array $forum Array of information about the forum
|
||||
* @return array Array containing formatted string for posts and string for threads
|
||||
*/
|
||||
function get_forum_unapproved($forum)
|
||||
{
|
||||
global $lang, $templates;
|
||||
|
||||
$unapproved_threads = $unapproved_posts = '';
|
||||
|
||||
// If the user is a moderator we need to fetch the count
|
||||
if(is_moderator($forum['fid'], "canviewunapprove"))
|
||||
{
|
||||
// Forum has one or more unaproved posts, format language string accordingly
|
||||
if($forum['unapprovedposts'])
|
||||
{
|
||||
if($forum['unapprovedposts'] > 1)
|
||||
{
|
||||
$unapproved_posts_count = $lang->sprintf($lang->forum_unapproved_posts_count, $forum['unapprovedposts']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$unapproved_posts_count = $lang->sprintf($lang->forum_unapproved_post_count, 1);
|
||||
}
|
||||
|
||||
$forum['unapprovedposts'] = my_number_format($forum['unapprovedposts']);
|
||||
eval("\$unapproved_posts = \"".$templates->get("forumbit_depth2_forum_unapproved_posts")."\";");
|
||||
}
|
||||
// Forum has one or more unapproved threads, format language string accordingly
|
||||
if($forum['unapprovedthreads'])
|
||||
{
|
||||
if($forum['unapprovedthreads'] > 1)
|
||||
{
|
||||
$unapproved_threads_count = $lang->sprintf($lang->forum_unapproved_threads_count, $forum['unapprovedthreads']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$unapproved_threads_count = $lang->sprintf($lang->forum_unapproved_thread_count, 1);
|
||||
}
|
||||
|
||||
$forum['unapprovedthreads'] = my_number_format($forum['unapprovedthreads']);
|
||||
eval("\$unapproved_threads = \"".$templates->get("forumbit_depth2_forum_unapproved_threads")."\";");
|
||||
}
|
||||
}
|
||||
return array(
|
||||
"unapproved_posts" => $unapproved_posts,
|
||||
"unapproved_threads" => $unapproved_threads
|
||||
);
|
||||
}
|
||||
260
webroot/forum/inc/functions_image.php
Normal file
260
webroot/forum/inc/functions_image.php
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates a thumbnail based on specified dimensions (supports png, jpg, and gif)
|
||||
*
|
||||
* @param string $file the full path to the original image
|
||||
* @param string $path the directory path to where to save the new image
|
||||
* @param string $filename the filename to save the new image as
|
||||
* @param integer $maxheight maximum hight dimension
|
||||
* @param integer $maxwidth maximum width dimension
|
||||
* @return array thumbnail on success, error code 4 on failure
|
||||
*/
|
||||
function generate_thumbnail($file, $path, $filename, $maxheight, $maxwidth)
|
||||
{
|
||||
$thumb = array();
|
||||
|
||||
if(!function_exists("imagecreate"))
|
||||
{
|
||||
$thumb['code'] = 3;
|
||||
return $thumb;
|
||||
}
|
||||
|
||||
$imgdesc = getimagesize($file);
|
||||
$imgwidth = $imgdesc[0];
|
||||
$imgheight = $imgdesc[1];
|
||||
$imgtype = $imgdesc[2];
|
||||
$imgattr = $imgdesc[3];
|
||||
$imgbits = $imgdesc['bits'];
|
||||
$imgchan = $imgdesc['channels'];
|
||||
|
||||
if($imgwidth == 0 || $imgheight == 0)
|
||||
{
|
||||
$thumb['code'] = 3;
|
||||
return $thumb;
|
||||
}
|
||||
if(($imgwidth >= $maxwidth) || ($imgheight >= $maxheight))
|
||||
{
|
||||
check_thumbnail_memory($imgwidth, $imgheight, $imgtype, $imgbits, $imgchan);
|
||||
|
||||
if($imgtype == 3)
|
||||
{
|
||||
if(@function_exists("imagecreatefrompng"))
|
||||
{
|
||||
$im = @imagecreatefrompng($file);
|
||||
}
|
||||
}
|
||||
elseif($imgtype == 2)
|
||||
{
|
||||
if(@function_exists("imagecreatefromjpeg"))
|
||||
{
|
||||
$im = @imagecreatefromjpeg($file);
|
||||
}
|
||||
}
|
||||
elseif($imgtype == 1)
|
||||
{
|
||||
if(@function_exists("imagecreatefromgif"))
|
||||
{
|
||||
$im = @imagecreatefromgif($file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$thumb['code'] = 3;
|
||||
return $thumb;
|
||||
}
|
||||
if(!$im)
|
||||
{
|
||||
$thumb['code'] = 3;
|
||||
return $thumb;
|
||||
}
|
||||
$scale = scale_image($imgwidth, $imgheight, $maxwidth, $maxheight);
|
||||
$thumbwidth = $scale['width'];
|
||||
$thumbheight = $scale['height'];
|
||||
$thumbim = @imagecreatetruecolor($thumbwidth, $thumbheight);
|
||||
|
||||
if(!$thumbim)
|
||||
{
|
||||
$thumbim = @imagecreate($thumbwidth, $thumbheight);
|
||||
$resized = true;
|
||||
}
|
||||
|
||||
// Attempt to preserve the transparency if there is any
|
||||
if($imgtype == 3)
|
||||
{
|
||||
// A PNG!
|
||||
imagealphablending($thumbim, false);
|
||||
imagefill($thumbim, 0, 0, imagecolorallocatealpha($thumbim, 0, 0, 0, 127));
|
||||
|
||||
// Save Alpha...
|
||||
imagesavealpha($thumbim, true);
|
||||
}
|
||||
elseif($imgtype == 1)
|
||||
{
|
||||
// Transparent GIF?
|
||||
$trans_color = imagecolortransparent($im);
|
||||
if($trans_color >= 0 && $trans_color < imagecolorstotal($im))
|
||||
{
|
||||
$trans = imagecolorsforindex($im, $trans_color);
|
||||
$new_trans_color = imagecolorallocate($thumbim, $trans['red'], $trans['blue'], $trans['green']);
|
||||
imagefill($thumbim, 0, 0, $new_trans_color);
|
||||
imagecolortransparent($thumbim, $new_trans_color);
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($resized))
|
||||
{
|
||||
@imagecopyresampled($thumbim, $im, 0, 0, 0, 0, $thumbwidth, $thumbheight, $imgwidth, $imgheight);
|
||||
}
|
||||
else
|
||||
{
|
||||
@imagecopyresized($thumbim, $im, 0, 0, 0, 0, $thumbwidth, $thumbheight, $imgwidth, $imgheight);
|
||||
}
|
||||
@imagedestroy($im);
|
||||
if(!function_exists("imagegif") && $imgtype == 1)
|
||||
{
|
||||
$filename = str_replace(".gif", ".jpg", $filename);
|
||||
}
|
||||
switch($imgtype)
|
||||
{
|
||||
case 1:
|
||||
if(function_exists("imagegif"))
|
||||
{
|
||||
@imagegif($thumbim, $path."/".$filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
@imagejpeg($thumbim, $path."/".$filename);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@imagejpeg($thumbim, $path."/".$filename);
|
||||
break;
|
||||
case 3:
|
||||
@imagepng($thumbim, $path."/".$filename);
|
||||
break;
|
||||
}
|
||||
@my_chmod($path."/".$filename, '0644');
|
||||
@imagedestroy($thumbim);
|
||||
$thumb['code'] = 1;
|
||||
$thumb['filename'] = $filename;
|
||||
return $thumb;
|
||||
}
|
||||
else
|
||||
{
|
||||
return array("code" => 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to allocate enough memory to generate the thumbnail
|
||||
*
|
||||
* @param integer $width width dimension
|
||||
* @param integer $height height dimension
|
||||
* @param string $type one of the IMAGETYPE_XXX constants indicating the type of the image
|
||||
* @param string $bitdepth the bits area the number of bits for each color
|
||||
* @param string $channels the channels - 3 for RGB pictures and 4 for CMYK pictures
|
||||
* @return bool
|
||||
*/
|
||||
function check_thumbnail_memory($width, $height, $type, $bitdepth, $channels)
|
||||
{
|
||||
if(!function_exists("memory_get_usage"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$memory_limit = @ini_get("memory_limit");
|
||||
if(!$memory_limit || $memory_limit == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$limit = preg_match("#^([0-9]+)\s?([kmg])b?$#i", trim(my_strtolower($memory_limit)), $matches);
|
||||
$memory_limit = (int)$memory_limit;
|
||||
if($matches[1] && $matches[2])
|
||||
{
|
||||
switch($matches[2])
|
||||
{
|
||||
case "k":
|
||||
$memory_limit = $matches[1] * 1024;
|
||||
break;
|
||||
case "m":
|
||||
$memory_limit = $matches[1] * 1048576;
|
||||
break;
|
||||
case "g":
|
||||
$memory_limit = $matches[1] * 1073741824;
|
||||
}
|
||||
}
|
||||
$current_usage = memory_get_usage();
|
||||
$free_memory = $memory_limit - $current_usage;
|
||||
|
||||
$thumbnail_memory = round(($width * $height * $bitdepth * $channels / 8) * 5);
|
||||
$thumbnail_memory += 2097152;
|
||||
|
||||
if($thumbnail_memory > $free_memory)
|
||||
{
|
||||
if($matches[1] && $matches[2])
|
||||
{
|
||||
switch($matches[2])
|
||||
{
|
||||
case "k":
|
||||
$memory_limit = ceil((($memory_limit+$thumbnail_memory) / 1024))."K";
|
||||
break;
|
||||
case "m":
|
||||
$memory_limit = ceil((($memory_limit+$thumbnail_memory) / 1048576))."M";
|
||||
break;
|
||||
case "g":
|
||||
$memory_limit = ceil((($memory_limit+$thumbnail_memory) / 1073741824))."G";
|
||||
}
|
||||
}
|
||||
|
||||
@ini_set("memory_limit", $memory_limit);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Figures out the correct dimensions to use
|
||||
*
|
||||
* @param integer $width current width dimension
|
||||
* @param integer $height current height dimension
|
||||
* @param integer $maxwidth max width dimension
|
||||
* @param integer $maxheight max height dimension
|
||||
* @return array correct height & width
|
||||
*/
|
||||
function scale_image($width, $height, $maxwidth, $maxheight)
|
||||
{
|
||||
$width = (int)$width;
|
||||
$height = (int)$height;
|
||||
|
||||
if(!$width) $width = $maxwidth;
|
||||
if(!$height) $height = $maxheight;
|
||||
|
||||
$newwidth = $width;
|
||||
$newheight = $height;
|
||||
|
||||
if($width > $maxwidth)
|
||||
{
|
||||
$newwidth = $maxwidth;
|
||||
$newheight = ceil(($height*(($maxwidth*100)/$width))/100);
|
||||
$height = $newheight;
|
||||
$width = $newwidth;
|
||||
}
|
||||
if($height > $maxheight)
|
||||
{
|
||||
$newheight = $maxheight;
|
||||
$newwidth = ceil(($width*(($maxheight*100)/$height))/100);
|
||||
}
|
||||
$ret['width'] = $newwidth;
|
||||
$ret['height'] = $newheight;
|
||||
return $ret;
|
||||
}
|
||||
365
webroot/forum/inc/functions_indicators.php
Normal file
365
webroot/forum/inc/functions_indicators.php
Normal file
@@ -0,0 +1,365 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mark a particular thread as read for the current user.
|
||||
*
|
||||
* @param int $tid The thread ID
|
||||
* @param int $fid The forum ID of the thread
|
||||
*/
|
||||
function mark_thread_read($tid, $fid)
|
||||
{
|
||||
global $mybb, $db;
|
||||
|
||||
// Can only do "true" tracking for registered users
|
||||
if($mybb->settings['threadreadcut'] > 0 && $mybb->user['uid'])
|
||||
{
|
||||
// For registered users, store the information in the database.
|
||||
switch($db->type)
|
||||
{
|
||||
case "pgsql":
|
||||
case "sqlite":
|
||||
$db->replace_query("threadsread", array('tid' => $tid, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW), array("tid", "uid"));
|
||||
break;
|
||||
default:
|
||||
$db->write_query("
|
||||
REPLACE INTO ".TABLE_PREFIX."threadsread (tid, uid, dateline)
|
||||
VALUES('$tid', '{$mybb->user['uid']}', '".TIME_NOW."')
|
||||
");
|
||||
}
|
||||
}
|
||||
// Default back to cookie marking
|
||||
else
|
||||
{
|
||||
my_set_array_cookie("threadread", $tid, TIME_NOW, -1);
|
||||
}
|
||||
|
||||
$unread_count = fetch_unread_count($fid);
|
||||
if($unread_count == 0)
|
||||
{
|
||||
mark_forum_read($fid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the number of unread threads for the current user in a particular forum.
|
||||
*
|
||||
* @param string $fid The forums (CSV list)
|
||||
* @return int The number of unread threads
|
||||
*/
|
||||
function fetch_unread_count($fid)
|
||||
{
|
||||
global $cache, $db, $mybb;
|
||||
|
||||
$forums_all = $forums_own = array();
|
||||
$forums = explode(',', $fid);
|
||||
foreach($forums as $forum)
|
||||
{
|
||||
$permissions = forum_permissions($forum);
|
||||
if(!empty($permissions['canonlyviewownthreads']))
|
||||
{
|
||||
$forums_own[] = $forum;
|
||||
}
|
||||
else
|
||||
{
|
||||
$forums_all[] = $forum;
|
||||
}
|
||||
}
|
||||
if(!empty($forums_own))
|
||||
{
|
||||
$where = "(fid IN (".implode(',', $forums_own).") AND uid = {$mybb->user['uid']})";
|
||||
$where2 = "(t.fid IN (".implode(',', $forums_own).") AND t.uid = {$mybb->user['uid']})";
|
||||
}
|
||||
if(!empty($forums_all))
|
||||
{
|
||||
if(isset($where))
|
||||
{
|
||||
$where = "({$where} OR fid IN (".implode(',', $forums_all)."))";
|
||||
$where2 = "({$where2} OR t.fid IN (".implode(',', $forums_all)."))";
|
||||
}
|
||||
else
|
||||
{
|
||||
$where = 'fid IN ('.implode(',', $forums_all).')';
|
||||
$where2 = 't.fid IN ('.implode(',', $forums_all).')';
|
||||
}
|
||||
}
|
||||
$cutoff = TIME_NOW-$mybb->settings['threadreadcut']*60*60*24;
|
||||
|
||||
if(!empty($permissions['canonlyviewownthreads']))
|
||||
{
|
||||
$onlyview = " AND uid = '{$mybb->user['uid']}'";
|
||||
$onlyview2 = " AND t.uid = '{$mybb->user['uid']}'";
|
||||
}
|
||||
|
||||
if($mybb->user['uid'] == 0)
|
||||
{
|
||||
$comma = '';
|
||||
$tids = '';
|
||||
$threadsread = $forumsread = array();
|
||||
|
||||
if(isset($mybb->cookies['mybb']['threadread']))
|
||||
{
|
||||
$threadsread = my_unserialize($mybb->cookies['mybb']['threadread']);
|
||||
}
|
||||
if(isset($mybb->cookies['mybb']['forumread']))
|
||||
{
|
||||
$forumsread = my_unserialize($mybb->cookies['mybb']['forumread']);
|
||||
}
|
||||
|
||||
if(!empty($threadsread))
|
||||
{
|
||||
foreach($threadsread as $key => $value)
|
||||
{
|
||||
$tids .= $comma.(int)$key;
|
||||
$comma = ',';
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($tids))
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
// We've read at least some threads, are they here?
|
||||
$query = $db->simple_select("threads", "lastpost, tid, fid", "visible=1 AND closed NOT LIKE 'moved|%' AND {$where} AND lastpost > '{$cutoff}'", array("limit" => 100));
|
||||
|
||||
while($thread = $db->fetch_array($query))
|
||||
{
|
||||
if((!isset($threadsread[$thread['tid']]) || $thread['lastpost'] > (int)$threadsread[$thread['tid']]) && (!isset($forumsread[$thread['fid']]) || $thread['lastpost'] > (int)$forumsread[$thread['fid']]))
|
||||
{
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
// Not read any threads?
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch($db->type)
|
||||
{
|
||||
case "pgsql":
|
||||
$query = $db->query("
|
||||
SELECT COUNT(t.tid) AS unread_count
|
||||
FROM ".TABLE_PREFIX."threads t
|
||||
LEFT JOIN ".TABLE_PREFIX."threadsread tr ON (tr.tid=t.tid AND tr.uid='{$mybb->user['uid']}')
|
||||
LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=t.fid AND fr.uid='{$mybb->user['uid']}')
|
||||
WHERE t.visible=1 AND t.closed NOT LIKE 'moved|%' AND {$where2} AND t.lastpost > COALESCE(tr.dateline,$cutoff) AND t.lastpost > COALESCE(fr.dateline,$cutoff) AND t.lastpost>$cutoff
|
||||
");
|
||||
break;
|
||||
default:
|
||||
$query = $db->query("
|
||||
SELECT COUNT(t.tid) AS unread_count
|
||||
FROM ".TABLE_PREFIX."threads t
|
||||
LEFT JOIN ".TABLE_PREFIX."threadsread tr ON (tr.tid=t.tid AND tr.uid='{$mybb->user['uid']}')
|
||||
LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=t.fid AND fr.uid='{$mybb->user['uid']}')
|
||||
WHERE t.visible=1 AND t.closed NOT LIKE 'moved|%' AND {$where2} AND t.lastpost > IFNULL(tr.dateline,$cutoff) AND t.lastpost > IFNULL(fr.dateline,$cutoff) AND t.lastpost>$cutoff
|
||||
");
|
||||
}
|
||||
return $db->fetch_field($query, "unread_count");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a particular forum as read.
|
||||
*
|
||||
* @param int $fid The forum ID
|
||||
*/
|
||||
function mark_forum_read($fid)
|
||||
{
|
||||
global $mybb, $db;
|
||||
|
||||
// Can only do "true" tracking for registered users
|
||||
if($mybb->settings['threadreadcut'] > 0 && $mybb->user['uid'])
|
||||
{
|
||||
// Experimental setting to mark parent forums as read
|
||||
$forums_to_read = array();
|
||||
|
||||
if($mybb->settings['readparentforums'])
|
||||
{
|
||||
$ignored_forums = array();
|
||||
$forums = array_reverse(explode(",", get_parent_list($fid)));
|
||||
|
||||
unset($forums[0]);
|
||||
if(!empty($forums))
|
||||
{
|
||||
$ignored_forums[] = $fid;
|
||||
|
||||
foreach($forums as $forum)
|
||||
{
|
||||
$fids = array($forum);
|
||||
$ignored_forums[] = $forum;
|
||||
|
||||
$children = explode(",", get_parent_list($forum));
|
||||
foreach($children as $child)
|
||||
{
|
||||
if(in_array($child, $ignored_forums))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$fids[] = $child;
|
||||
$ignored_forums[] = $child;
|
||||
}
|
||||
|
||||
if(fetch_unread_count(implode(",", $fids)) == 0)
|
||||
{
|
||||
$forums_to_read[] = $forum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch($db->type)
|
||||
{
|
||||
case "pgsql":
|
||||
case "sqlite":
|
||||
add_shutdown(array($db, "replace_query"), array("forumsread", array('fid' => $fid, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW), array("fid", "uid")));
|
||||
|
||||
if(!empty($forums_to_read))
|
||||
{
|
||||
foreach($forums_to_read as $forum)
|
||||
{
|
||||
add_shutdown(array($db, "replace_query"), array("forumsread", array('fid' => $forum, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW), array('fid', 'uid')));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$child_sql = '';
|
||||
if(!empty($forums_to_read))
|
||||
{
|
||||
foreach($forums_to_read as $forum)
|
||||
{
|
||||
$child_sql .= ", ('{$forum}', '{$mybb->user['uid']}', '".TIME_NOW."')";
|
||||
}
|
||||
}
|
||||
|
||||
$db->shutdown_query("
|
||||
REPLACE INTO ".TABLE_PREFIX."forumsread (fid, uid, dateline)
|
||||
VALUES('{$fid}', '{$mybb->user['uid']}', '".TIME_NOW."'){$child_sql}
|
||||
");
|
||||
}
|
||||
}
|
||||
// Mark in a cookie
|
||||
else
|
||||
{
|
||||
my_set_array_cookie("forumread", $fid, TIME_NOW, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks all forums as read.
|
||||
*
|
||||
*/
|
||||
function mark_all_forums_read()
|
||||
{
|
||||
global $mybb, $db, $cache;
|
||||
|
||||
// Can only do "true" tracking for registered users
|
||||
if($mybb->user['uid'] > 0)
|
||||
{
|
||||
$db->update_query("users", array('lastvisit' => TIME_NOW), "uid='".$mybb->user['uid']."'");
|
||||
require_once MYBB_ROOT."inc/functions_user.php";
|
||||
update_pm_count('', 2);
|
||||
|
||||
if($mybb->settings['threadreadcut'] > 0)
|
||||
{
|
||||
// Need to loop through all forums and mark them as read
|
||||
$forums = $cache->read('forums');
|
||||
|
||||
$update_count = ceil(count($forums)/20);
|
||||
|
||||
if($update_count < 15)
|
||||
{
|
||||
$update_count = 15;
|
||||
}
|
||||
|
||||
switch($db->type)
|
||||
{
|
||||
case "pgsql":
|
||||
case "sqlite":
|
||||
$mark_query = array();
|
||||
break;
|
||||
default:
|
||||
$mark_query = '';
|
||||
}
|
||||
|
||||
$done = 0;
|
||||
foreach(array_keys($forums) as $fid)
|
||||
{
|
||||
switch($db->type)
|
||||
{
|
||||
case "pgsql":
|
||||
case "sqlite":
|
||||
$mark_query[] = array('fid' => $fid, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW);
|
||||
break;
|
||||
default:
|
||||
if($mark_query != '')
|
||||
{
|
||||
$mark_query .= ',';
|
||||
}
|
||||
$mark_query .= "('{$fid}', '{$mybb->user['uid']}', '".TIME_NOW."')";
|
||||
}
|
||||
++$done;
|
||||
|
||||
// Only do this in loops of $update_count, save query time
|
||||
if($done % $update_count)
|
||||
{
|
||||
switch($db->type)
|
||||
{
|
||||
case "pgsql":
|
||||
case "sqlite":
|
||||
foreach($mark_query as $replace_query)
|
||||
{
|
||||
add_shutdown(array($db, "replace_query"), array("forumsread", $replace_query, array("fid", "uid")));
|
||||
}
|
||||
$mark_query = array();
|
||||
break;
|
||||
default:
|
||||
$db->shutdown_query("
|
||||
REPLACE INTO ".TABLE_PREFIX."forumsread (fid, uid, dateline)
|
||||
VALUES {$mark_query}
|
||||
");
|
||||
$mark_query = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($mark_query))
|
||||
{
|
||||
switch($db->type)
|
||||
{
|
||||
case "pgsql":
|
||||
case "sqlite":
|
||||
foreach($mark_query as $replace_query)
|
||||
{
|
||||
add_shutdown(array($db, "replace_query"), array("forumsread", $replace_query, array("fid", "uid")));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$db->shutdown_query("
|
||||
REPLACE INTO ".TABLE_PREFIX."forumsread (fid, uid, dateline)
|
||||
VALUES {$mark_query}
|
||||
");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
my_setcookie("mybb[readallforums]", 1);
|
||||
my_setcookie("mybb[lastvisit]", TIME_NOW);
|
||||
|
||||
my_unsetcookie("mybb[threadread]");
|
||||
my_unsetcookie("mybb[forumread]");
|
||||
}
|
||||
}
|
||||
222
webroot/forum/inc/functions_massmail.php
Normal file
222
webroot/forum/inc/functions_massmail.php
Normal file
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Build the mass email SQL query for the specified conditions.
|
||||
*
|
||||
* @param array $conditions Array of conditions to match users against.
|
||||
* @return string The generated search SQL
|
||||
*/
|
||||
function build_mass_mail_query($conditions)
|
||||
{
|
||||
global $db;
|
||||
|
||||
if(!is_array($conditions))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
$search_sql = 'u.allownotices=1';
|
||||
|
||||
// List of valid LIKE search fields
|
||||
$user_like_fields = array("username", "email");
|
||||
foreach($user_like_fields as $search_field)
|
||||
{
|
||||
if($conditions[$search_field])
|
||||
{
|
||||
$search_sql .= " AND u.{$search_field} LIKE '%".$db->escape_string_like($conditions[$search_field])."%'";
|
||||
}
|
||||
}
|
||||
|
||||
// LESS THAN or GREATER THAN
|
||||
$direction_fields = array("postnum");
|
||||
foreach($direction_fields as $search_field)
|
||||
{
|
||||
$direction_field = $search_field."_dir";
|
||||
if(!empty($conditions[$search_field]) && $conditions[$direction_field])
|
||||
{
|
||||
switch($conditions[$direction_field])
|
||||
{
|
||||
case "greater_than":
|
||||
$direction = ">";
|
||||
break;
|
||||
case "less_than":
|
||||
$direction = "<";
|
||||
break;
|
||||
default:
|
||||
$direction = "=";
|
||||
}
|
||||
$search_sql .= " AND u.{$search_field}{$direction}'".(int)$conditions[$search_field]."'";
|
||||
}
|
||||
}
|
||||
|
||||
// Time-based search fields
|
||||
$time_fields = array("regdate", "lastactive");
|
||||
foreach($time_fields as $search_field)
|
||||
{
|
||||
$time_field = $search_field."_date";
|
||||
$direction_field = $search_field."_dir";
|
||||
if(!empty($conditions[$search_field]) && $conditions[$time_field] && $conditions[$direction_field])
|
||||
{
|
||||
switch($conditions[$time_field])
|
||||
{
|
||||
case "hours":
|
||||
$date = $conditions[$search_field]*60*60;
|
||||
break;
|
||||
case "days":
|
||||
$date = $conditions[$search_field]*60*60*24;
|
||||
break;
|
||||
case "weeks":
|
||||
$date = $conditions[$search_field]*60*60*24*7;
|
||||
break;
|
||||
case "months":
|
||||
$date = $conditions[$search_field]*60*60*24*30;
|
||||
break;
|
||||
case "years":
|
||||
$date = $conditions[$search_field]*60*60*24*365;
|
||||
break;
|
||||
default:
|
||||
$date = $conditions[$search_field]*60*60*24;
|
||||
}
|
||||
|
||||
switch($conditions[$direction_field])
|
||||
{
|
||||
case "less_than":
|
||||
$direction = ">";
|
||||
break;
|
||||
case "more_than":
|
||||
$direction = "<";
|
||||
break;
|
||||
default:
|
||||
$direction = "<";
|
||||
}
|
||||
$search_sql .= " AND u.{$search_field}{$direction}'".(TIME_NOW-$date)."'";
|
||||
}
|
||||
}
|
||||
|
||||
// Usergroup based searching
|
||||
if($conditions['usergroup'])
|
||||
{
|
||||
if(!is_array($conditions['usergroup']))
|
||||
{
|
||||
$conditions['usergroup'] = array($conditions['usergroup']);
|
||||
}
|
||||
|
||||
$conditions['usergroup'] = array_map('intval', $conditions['usergroup']);
|
||||
|
||||
$additional_sql = '';
|
||||
foreach($conditions['usergroup'] as $usergroup)
|
||||
{
|
||||
switch($db->type)
|
||||
{
|
||||
case "pgsql":
|
||||
case "sqlite":
|
||||
$additional_sql .= " OR ','||additionalgroups||',' LIKE '%,{$usergroup},%'";
|
||||
break;
|
||||
default:
|
||||
$additional_sql .= " OR CONCAT(',',additionalgroups,',') LIKE '%,{$usergroup},%'";
|
||||
}
|
||||
}
|
||||
$search_sql .= " AND (u.usergroup IN (".implode(",", $conditions['usergroup']).") {$additional_sql})";
|
||||
}
|
||||
|
||||
return $search_sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a text based version of a HTML mass email.
|
||||
*
|
||||
* @param string $message The HTML version.
|
||||
* @return string The generated text based version.
|
||||
*/
|
||||
function create_text_message($message)
|
||||
{
|
||||
// Cut out all current line breaks
|
||||
// Makes links CONTENT (link)
|
||||
$message = make_pretty_links($message);
|
||||
$message = str_replace(array("\r\n", "\n"), "\n", $message);
|
||||
$message = preg_replace("#</p>#i", "\n\n", $message);
|
||||
$message = preg_replace("#<br( \/?)>#i", "\n", $message);
|
||||
$message = preg_replace("#<p[^>]*?>#i", "", $message);
|
||||
$message = preg_replace("#<hr[^>]*?>\s*#i", "-----------\n", $message);
|
||||
$message = html_entity_decode($message);
|
||||
$message = str_replace("\t", "", $message);
|
||||
do
|
||||
{
|
||||
$message = str_replace(" ", " ", $message);
|
||||
}
|
||||
while(strpos($message, " ") !== false);
|
||||
|
||||
$search = array('@<script[^>]*?>.*?</script>@si', // Strip out javascript
|
||||
'@<style[^>]*?>.*?</style>@siU', // Strip style tags properly
|
||||
'@<title[^>]*?>.*?</title>@siU', // Strip title tags
|
||||
'@<[\/\!]*?[^<>]*?>@si', // Strip out HTML tags
|
||||
'@<![\s\S]*?--[ \t\n\r]*>@' // Strip multi-line comments including CDATA
|
||||
);
|
||||
$message = preg_replace($search, '', $message);
|
||||
$message = preg_replace("#\n\n+#", "\n\n", $message);
|
||||
$message = preg_replace("#^\s+#is", "", $message);
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates friendly links for a text based version of a mass email from the HTML version.
|
||||
*
|
||||
* @param string $message_html The HTML version.
|
||||
* @return string The version with the friendly links and all <a> tags stripped.
|
||||
*/
|
||||
function make_pretty_links($message_html)
|
||||
{
|
||||
do
|
||||
{
|
||||
$start = stripos($message_html, "<a");
|
||||
if($start === false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
$end = stripos($message_html, "</a>", $start);
|
||||
if($end === false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
$a_href = substr($message_html, $start, ($end-$start));
|
||||
|
||||
preg_match("#href=\"?([^\"> ]+)\"?#i", $a_href, $href_matches);
|
||||
if(!$href_matches[1])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$link = $href_matches[1];
|
||||
|
||||
$contents = strip_tags($a_href);
|
||||
if(!$contents)
|
||||
{
|
||||
preg_match("#alt=\"?([^\">]+)\"?#i", $a_href, $matches2);
|
||||
if($matches2[1])
|
||||
{
|
||||
$contents = $matches2[1];
|
||||
}
|
||||
if(!$contents)
|
||||
{
|
||||
preg_match("#title=\"?([^\">]+)\"?#i", $a_href, $matches2);
|
||||
if($matches2[1])
|
||||
{
|
||||
$contents = $matches2[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$replaced_link = $contents." ({$link}) ";
|
||||
|
||||
$message_html = substr_replace($message_html, $replaced_link, $start, ($end-$start));
|
||||
} while(true);
|
||||
return $message_html;
|
||||
}
|
||||
333
webroot/forum/inc/functions_modcp.php
Normal file
333
webroot/forum/inc/functions_modcp.php
Normal file
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check if the current user has permission to perform a ModCP action on another user
|
||||
*
|
||||
* @param int $uid The user ID to perform the action on.
|
||||
* @return boolean True if the user has necessary permissions
|
||||
*/
|
||||
function modcp_can_manage_user($uid)
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
$user_permissions = user_permissions($uid);
|
||||
|
||||
// Current user is only a local moderator or use with ModCP permissions, cannot manage super mods or admins
|
||||
if($mybb->usergroup['issupermod'] == 0 && ($user_permissions['issupermod'] == 1 || $user_permissions['cancp'] == 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Current user is a super mod or is an administrator
|
||||
else if($user_permissions['cancp'] == 1 && ($mybb->usergroup['cancp'] != 1 || (is_super_admin($uid) && !is_super_admin($mybb->user['uid']))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch forums the moderator can manage announcements to
|
||||
*
|
||||
* @param int $pid (Optional) The parent forum ID
|
||||
* @param int $depth (Optional) The depth from parent forum the moderator can manage to
|
||||
*/
|
||||
function fetch_forum_announcements($pid=0, $depth=1)
|
||||
{
|
||||
global $mybb, $db, $lang, $theme, $announcements, $templates, $announcements_forum, $moderated_forums, $unviewableforums, $parser;
|
||||
static $forums_by_parent, $forum_cache, $parent_forums;
|
||||
|
||||
if(!is_array($forum_cache))
|
||||
{
|
||||
$forum_cache = cache_forums();
|
||||
}
|
||||
if(!is_array($parent_forums) && $mybb->usergroup['issupermod'] != 1)
|
||||
{
|
||||
// Get a list of parentforums to show for normal moderators
|
||||
$parent_forums = array();
|
||||
foreach($moderated_forums as $mfid)
|
||||
{
|
||||
$parent_forums = array_merge($parent_forums, explode(',', $forum_cache[$mfid]['parentlist']));
|
||||
}
|
||||
}
|
||||
if(!is_array($forums_by_parent))
|
||||
{
|
||||
foreach($forum_cache as $forum)
|
||||
{
|
||||
$forums_by_parent[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum;
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_array($forums_by_parent[$pid]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($forums_by_parent[$pid] as $children)
|
||||
{
|
||||
foreach($children as $forum)
|
||||
{
|
||||
if($forum['linkto'] || (is_array($unviewableforums) && in_array($forum['fid'], $unviewableforums)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if($forum['active'] == 0 || !is_moderator($forum['fid'], "canmanageannouncements"))
|
||||
{
|
||||
// Check if this forum is a parent of a moderated forum
|
||||
if(is_array($parent_forums) && in_array($forum['fid'], $parent_forums))
|
||||
{
|
||||
// A child is moderated, so print out this forum's title. RECURSE!
|
||||
$trow = alt_trow();
|
||||
eval("\$announcements_forum .= \"".$templates->get("modcp_announcements_forum_nomod")."\";");
|
||||
}
|
||||
else
|
||||
{
|
||||
// No subforum is moderated by this mod, so safely continue
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This forum is moderated by the user, so print out the forum's title, and its announcements
|
||||
$trow = alt_trow();
|
||||
|
||||
$padding = 40*($depth-1);
|
||||
|
||||
eval("\$announcements_forum .= \"".$templates->get("modcp_announcements_forum")."\";");
|
||||
|
||||
if(isset($announcements[$forum['fid']]))
|
||||
{
|
||||
foreach($announcements[$forum['fid']] as $aid => $announcement)
|
||||
{
|
||||
$trow = alt_trow();
|
||||
|
||||
if($announcement['enddate'] < TIME_NOW && $announcement['enddate'] != 0)
|
||||
{
|
||||
eval("\$icon = \"".$templates->get("modcp_announcements_announcement_expired")."\";");
|
||||
}
|
||||
else
|
||||
{
|
||||
eval("\$icon = \"".$templates->get("modcp_announcements_announcement_active")."\";");
|
||||
}
|
||||
|
||||
$subject = htmlspecialchars_uni($parser->parse_badwords($announcement['subject']));
|
||||
|
||||
eval("\$announcements_forum .= \"".$templates->get("modcp_announcements_announcement")."\";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build the list for any sub forums of this forum
|
||||
if(isset($forums_by_parent[$forum['fid']]))
|
||||
{
|
||||
fetch_forum_announcements($forum['fid'], $depth+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send reported content to moderators
|
||||
*
|
||||
* @param array $report Array of reported content
|
||||
* @param string $report_type Type of content being reported
|
||||
* @return bool|array PM Information or false
|
||||
*/
|
||||
function send_report($report, $report_type='post')
|
||||
{
|
||||
global $db, $lang, $forum, $mybb, $post, $thread, $reputation, $user, $plugins;
|
||||
|
||||
$report_reason = '';
|
||||
if($report['reasonid'])
|
||||
{
|
||||
$query = $db->simple_select("reportreasons", "title", "rid = '".(int)$report['reasonid']."'", array('limit' => 1));
|
||||
$reason = $db->fetch_array($query);
|
||||
|
||||
$lang->load('report');
|
||||
|
||||
$report_reason = $lang->parse($reason['title']);
|
||||
}
|
||||
|
||||
if($report['reason'])
|
||||
{
|
||||
$report_reason = $lang->sprintf($lang->email_report_comment_extra, $report_reason, $report['reason']);
|
||||
}
|
||||
|
||||
$modsjoin = $modswhere = '';
|
||||
if(!empty($forum['parentlist']))
|
||||
{
|
||||
$modswhere = "m.fid IN ({$forum['parentlist']}) OR ";
|
||||
|
||||
if($db->type == 'pgsql' || $db->type == 'sqlite')
|
||||
{
|
||||
$modsjoin = "LEFT JOIN {$db->table_prefix}moderators m ON (m.id = u.uid AND m.isgroup = 0) OR ((m.id = u.usergroup OR ',' || u.additionalgroups || ',' LIKE '%,' || m.id || ',%') AND m.isgroup = 1)";
|
||||
}
|
||||
else
|
||||
{
|
||||
$modsjoin = "LEFT JOIN {$db->table_prefix}moderators m ON (m.id = u.uid AND m.isgroup = 0) OR ((m.id = u.usergroup OR CONCAT(',', u.additionalgroups, ',') LIKE CONCAT('%,', m.id, ',%')) AND m.isgroup = 1)";
|
||||
}
|
||||
}
|
||||
|
||||
switch($db->type)
|
||||
{
|
||||
case "pgsql":
|
||||
case "sqlite":
|
||||
$query = $db->query("
|
||||
SELECT DISTINCT u.username, u.email, u.receivepms, u.uid
|
||||
FROM {$db->table_prefix}users u
|
||||
{$modsjoin}
|
||||
LEFT JOIN {$db->table_prefix}usergroups g ON (',' || u.additionalgroups || ',' LIKE '%,' || g.gid || ',%' OR g.gid = u.usergroup)
|
||||
WHERE {$modswhere}g.cancp = 1 OR g.issupermod = 1
|
||||
");
|
||||
break;
|
||||
default:
|
||||
$query = $db->query("
|
||||
SELECT DISTINCT u.username, u.email, u.receivepms, u.uid
|
||||
FROM {$db->table_prefix}users u
|
||||
{$modsjoin}
|
||||
LEFT JOIN {$db->table_prefix}usergroups g ON (CONCAT(',', u.additionalgroups, ',') LIKE CONCAT('%,', g.gid, ',%') OR g.gid = u.usergroup)
|
||||
WHERE {$modswhere}g.cancp = 1 OR g.issupermod = 1
|
||||
");
|
||||
}
|
||||
|
||||
$lang_string_subject = "emailsubject_report{$report_type}";
|
||||
$lang_string_message = "email_report{$report_type}";
|
||||
|
||||
if(empty($lang->$lang_string_subject) || empty($lang->$lang_string_message))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
global $send_report_subject, $send_report_url;
|
||||
|
||||
switch($report_type)
|
||||
{
|
||||
case 'post':
|
||||
$send_report_subject = $post['subject'];
|
||||
$send_report_url = str_replace('&', '&', get_post_link($post['pid'], $thread['tid'])."#pid".$post['pid']);
|
||||
break;
|
||||
case 'profile':
|
||||
$send_report_subject = $user['username'];
|
||||
$send_report_url = str_replace('&', '&', get_profile_link($user['uid']));
|
||||
break;
|
||||
case 'reputation':
|
||||
$from_user = get_user($reputation['adduid']);
|
||||
$send_report_subject = $from_user['username'];
|
||||
$send_report_url = "reputation.php?uid={$reputation['uid']}#rid{$reputation['rid']}";
|
||||
break;
|
||||
}
|
||||
|
||||
$plugins->run_hooks("send_report_report_type");
|
||||
|
||||
$emailsubject = $lang->sprintf($lang->$lang_string_subject, $mybb->settings['bbname']);
|
||||
$emailmessage = $lang->sprintf($lang->$lang_string_message, $mybb->user['username'], $mybb->settings['bbname'], $send_report_subject, $mybb->settings['bburl'], $send_report_url, $report_reason);
|
||||
$pm_recipients = array();
|
||||
|
||||
while($mod = $db->fetch_array($query))
|
||||
{
|
||||
if($mybb->settings['reportmethod'] == "pms" && $mod['receivepms'] != 0 && $mybb->settings['enablepms'] != 0)
|
||||
{
|
||||
$pm_recipients[] = $mod['uid'];
|
||||
}
|
||||
else
|
||||
{
|
||||
my_mail($mod['email'], $emailsubject, $emailmessage);
|
||||
}
|
||||
}
|
||||
|
||||
if(count($pm_recipients) > 0)
|
||||
{
|
||||
require_once MYBB_ROOT."inc/datahandlers/pm.php";
|
||||
$pmhandler = new PMDataHandler();
|
||||
|
||||
$pm = array(
|
||||
"subject" => $emailsubject,
|
||||
"message" => $emailmessage,
|
||||
"icon" => 0,
|
||||
"fromid" => $mybb->user['uid'],
|
||||
"toid" => $pm_recipients,
|
||||
"ipaddress" => $mybb->session->packedip
|
||||
);
|
||||
|
||||
$pmhandler->admin_override = true;
|
||||
$pmhandler->set_data($pm);
|
||||
|
||||
// Now let the pm handler do all the hard work.
|
||||
if(!$pmhandler->validate_pm())
|
||||
{
|
||||
// Force it to valid to just get it out of here
|
||||
$pmhandler->is_validated = true;
|
||||
$pmhandler->errors = array();
|
||||
}
|
||||
|
||||
$pminfo = $pmhandler->insert_pm();
|
||||
return $pminfo;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a report
|
||||
*
|
||||
* @param array $report Array of reported content
|
||||
* @param string $type Type of content being reported
|
||||
* @return int Report ID
|
||||
*/
|
||||
function add_report($report, $type = 'post')
|
||||
{
|
||||
global $cache, $db, $mybb;
|
||||
|
||||
$insert_array = array(
|
||||
'id' => (int)$report['id'],
|
||||
'id2' => (int)$report['id2'],
|
||||
'id3' => (int)$report['id3'],
|
||||
'uid' => (int)$report['uid'],
|
||||
'reportstatus' => 0,
|
||||
'reasonid' => (int)$report['reasonid'],
|
||||
'reason' => $db->escape_string($report['reason']),
|
||||
'type' => $db->escape_string($type),
|
||||
'reports' => 1,
|
||||
'dateline' => TIME_NOW,
|
||||
'lastreport' => TIME_NOW,
|
||||
'reporters' => $db->escape_string(my_serialize(array($report['uid'])))
|
||||
);
|
||||
|
||||
if($mybb->settings['reportmethod'] == "email" || $mybb->settings['reportmethod'] == "pms")
|
||||
{
|
||||
send_report($report, $type);
|
||||
}
|
||||
|
||||
$rid = $db->insert_query("reportedcontent", $insert_array);
|
||||
$cache->update_reportedcontent();
|
||||
|
||||
return $rid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing report
|
||||
*
|
||||
* @param array $report Array of reported content
|
||||
* @return bool true
|
||||
*/
|
||||
function update_report($report)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$update_array = array(
|
||||
'reports' => ++$report['reports'],
|
||||
'lastreport' => TIME_NOW,
|
||||
'reporters' => $db->escape_string(my_serialize($report['reporters']))
|
||||
);
|
||||
|
||||
$db->update_query("reportedcontent", $update_array, "rid = '{$report['rid']}'");
|
||||
return true;
|
||||
}
|
||||
1199
webroot/forum/inc/functions_online.php
Normal file
1199
webroot/forum/inc/functions_online.php
Normal file
File diff suppressed because it is too large
Load Diff
1059
webroot/forum/inc/functions_post.php
Normal file
1059
webroot/forum/inc/functions_post.php
Normal file
File diff suppressed because it is too large
Load Diff
225
webroot/forum/inc/functions_posting.php
Normal file
225
webroot/forum/inc/functions_posting.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Selectively removes quote tags from a message, depending on its nested depth. This is to be used with reply with quote functions.
|
||||
* For malformed quote tag structures, will try to simulate how MyBB's parser handles the issue, but is slightly inaccurate.
|
||||
* Examples, with a cutoff depth of 2:
|
||||
* #1. INPUT: [quote]a[quote=me]b[quote]c[/quote][/quote][/quote]
|
||||
* OUTPUT: [quote]a[quote=me]b[/quote][/quote]
|
||||
* #2. INPUT: [quote=a][quote=b][quote=c][quote=d][/quote][quote=e][/quote][/quote][quote=f][/quote][/quote]
|
||||
* OUTPUT: [quote=a][quote=b][/quote][quote=f][/quote][/quote]
|
||||
*
|
||||
* @param string $text the message from which quotes are to be removed
|
||||
* @param integer $rmdepth nested depth at which quotes should be removed; if none supplied, will use MyBB's default; must be at least 0
|
||||
* @return string the original message passed in $text, but with quote tags selectively removed
|
||||
*/
|
||||
function remove_message_quotes(&$text, $rmdepth=null)
|
||||
{
|
||||
if(!$text)
|
||||
{
|
||||
return $text;
|
||||
}
|
||||
if(!isset($rmdepth))
|
||||
{
|
||||
global $mybb;
|
||||
$rmdepth = $mybb->settings['maxquotedepth'];
|
||||
}
|
||||
$rmdepth = (int)$rmdepth;
|
||||
|
||||
// find all tokens
|
||||
// note, at various places, we use the prefix "s" to denote "start" (ie [quote]) and "e" to denote "end" (ie [/quote])
|
||||
preg_match_all("#\[quote(=(?:"|\"|')?.*?(?:"|\"|')?)?\]#si", $text, $smatches, PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);
|
||||
preg_match_all("#\[/quote\]#i", $text, $ematches, PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);
|
||||
|
||||
if(empty($smatches) || empty($ematches))
|
||||
{
|
||||
return $text;
|
||||
}
|
||||
|
||||
// make things easier by only keeping offsets
|
||||
$soffsets = $eoffsets = array();
|
||||
foreach($smatches[0] as $id => $match)
|
||||
{
|
||||
$soffsets[] = $match[1];
|
||||
}
|
||||
// whilst we loop, also remove unnecessary end tokens at the start of string
|
||||
$first_token = $soffsets[0];
|
||||
foreach($ematches[0] as $id => $match)
|
||||
{
|
||||
if($match[1] > $first_token)
|
||||
{
|
||||
$eoffsets[] = $match[1];
|
||||
}
|
||||
}
|
||||
unset($smatches, $ematches);
|
||||
|
||||
|
||||
// elmininate malformed quotes by parsing like the parser does (preg_replace in a while loop)
|
||||
// NOTE: this is slightly inaccurate because the parser considers [quote] and [quote=...] to be different things
|
||||
$good_offsets = array();
|
||||
while(!empty($soffsets) && !empty($eoffsets)) // don't rely on this condition - an end offset before the start offset will cause this to loop indefinitely
|
||||
{
|
||||
$last_offset = 0;
|
||||
foreach($soffsets as $sk => &$soffset)
|
||||
{
|
||||
if($soffset >= $last_offset)
|
||||
{
|
||||
// search for corresponding eoffset
|
||||
foreach($eoffsets as $ek => &$eoffset) // use foreach instead of for to get around indexing issues with unset
|
||||
{
|
||||
if($eoffset > $soffset)
|
||||
{
|
||||
// we've found a pair
|
||||
$good_offsets[$soffset] = 1;
|
||||
$good_offsets[$eoffset] = -1;
|
||||
$last_offset = $eoffset;
|
||||
|
||||
unset($soffsets[$sk], $eoffsets[$ek]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove any end offsets occurring before start offsets
|
||||
$first_start = reset($soffsets);
|
||||
foreach($eoffsets as $ek => &$eoffset)
|
||||
{
|
||||
if($eoffset < $first_start)
|
||||
{
|
||||
unset($eoffsets[$ek]);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// we don't need to remove start offsets after the last end offset, because the loop will deplete something before that
|
||||
}
|
||||
|
||||
if(empty($good_offsets))
|
||||
{
|
||||
return $text;
|
||||
}
|
||||
ksort($good_offsets);
|
||||
|
||||
|
||||
// we now have a list of all the ordered tokens, ready to go through
|
||||
$depth = 0;
|
||||
$remove_regions = array();
|
||||
$tmp_start = 0;
|
||||
foreach($good_offsets as $offset => $dincr)
|
||||
{
|
||||
if($depth == $rmdepth && $dincr == 1)
|
||||
{
|
||||
$tmp_start = $offset;
|
||||
}
|
||||
$depth += $dincr;
|
||||
if($depth == $rmdepth && $dincr == -1)
|
||||
{
|
||||
$remove_regions[] = array($tmp_start, $offset);
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($remove_regions))
|
||||
{
|
||||
return $text;
|
||||
}
|
||||
|
||||
// finally, remove the quotes from the string
|
||||
$newtext = '';
|
||||
$cpy_start = 0;
|
||||
foreach($remove_regions as &$region)
|
||||
{
|
||||
$newtext .= substr($text, $cpy_start, $region[0]-$cpy_start);
|
||||
$cpy_start = $region[1]+8; // 8 = strlen('[/quote]')
|
||||
// clean up newlines
|
||||
$next_char = $text{$region[1]+8};
|
||||
if($next_char == "\r" || $next_char == "\n")
|
||||
{
|
||||
++$cpy_start;
|
||||
if($next_char == "\r" && $text{$region[1]+9} == "\n")
|
||||
{
|
||||
++$cpy_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
// append remaining end text
|
||||
if(strlen($text) != $cpy_start)
|
||||
{
|
||||
$newtext .= substr($text, $cpy_start);
|
||||
}
|
||||
|
||||
// we're done
|
||||
return $newtext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs cleanup of a quoted message, such as replacing /me commands, before presenting quoted post to the user.
|
||||
*
|
||||
* @param array $quoted_post quoted post info, taken from the DB (requires the 'message', 'username', 'pid' and 'dateline' entries to be set; will use 'userusername' if present. requires 'quote_is_pm' if quote message is from a private message)
|
||||
* @param boolean $remove_message_quotes whether to call remove_message_quotes() on the quoted message
|
||||
* @return string the cleaned up message, wrapped in a quote tag
|
||||
*/
|
||||
|
||||
function parse_quoted_message(&$quoted_post, $remove_message_quotes=true)
|
||||
{
|
||||
global $parser, $lang, $plugins;
|
||||
if(!isset($parser))
|
||||
{
|
||||
require_once MYBB_ROOT."inc/class_parser.php";
|
||||
$parser = new postParser;
|
||||
}
|
||||
|
||||
// Swap username over if we have a registered user
|
||||
if($quoted_post['userusername'])
|
||||
{
|
||||
$quoted_post['username'] = $quoted_post['userusername'];
|
||||
}
|
||||
// Clean up the message
|
||||
$quoted_post['message'] = preg_replace(array(
|
||||
'#(^|\r|\n)/me ([^\r\n<]*)#i',
|
||||
'#(^|\r|\n)/slap ([^\r\n<]*)#i',
|
||||
'#\[attachment=([0-9]+?)\]#i'
|
||||
), array(
|
||||
"\\1* {$quoted_post['username']} \\2",
|
||||
"\\1* {$quoted_post['username']} {$lang->slaps} \\2 {$lang->with_trout}",
|
||||
"",
|
||||
), $quoted_post['message']);
|
||||
$quoted_post['message'] = $parser->parse_badwords($quoted_post['message']);
|
||||
|
||||
if($remove_message_quotes)
|
||||
{
|
||||
global $mybb;
|
||||
$max_quote_depth = (int)$mybb->settings['maxquotedepth'];
|
||||
if($max_quote_depth)
|
||||
{
|
||||
$quoted_post['message'] = remove_message_quotes($quoted_post['message'], $max_quote_depth-1); // we're wrapping the message in a [quote] tag, so take away one quote depth level
|
||||
}
|
||||
}
|
||||
|
||||
$quoted_post = $plugins->run_hooks("parse_quoted_message", $quoted_post);
|
||||
|
||||
$extra = '';
|
||||
if(empty($quoted_post['quote_is_pm']))
|
||||
{
|
||||
$extra = " pid='{$quoted_post['pid']}' dateline='{$quoted_post['dateline']}'";
|
||||
}
|
||||
|
||||
$quote_char = '"';
|
||||
if(strpos($quoted_post['username'], '"') !== false)
|
||||
{
|
||||
$quote_char = "'";
|
||||
}
|
||||
|
||||
return "[quote={$quote_char}{$quoted_post['username']}{$quote_char}{$extra}]\n{$quoted_post['message']}\n[/quote]\n\n";
|
||||
}
|
||||
|
||||
134
webroot/forum/inc/functions_rebuild.php
Normal file
134
webroot/forum/inc/functions_rebuild.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Completely recount the board statistics (useful if they become out of sync)
|
||||
*/
|
||||
function rebuild_stats()
|
||||
{
|
||||
global $db;
|
||||
|
||||
$query = $db->simple_select("forums", "SUM(threads) AS numthreads, SUM(posts) AS numposts, SUM(unapprovedthreads) AS numunapprovedthreads, SUM(unapprovedposts) AS numunapprovedposts, SUM(deletedthreads) AS numdeletedthreads, SUM(deletedposts) AS numdeletedposts");
|
||||
$stats = $db->fetch_array($query);
|
||||
|
||||
$query = $db->simple_select("users", "COUNT(uid) AS users");
|
||||
$stats['numusers'] = $db->fetch_field($query, 'users');
|
||||
|
||||
update_stats($stats, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely rebuild the counters for a particular forum (useful if they become out of sync)
|
||||
*
|
||||
* @param int $fid The forum ID
|
||||
*/
|
||||
function rebuild_forum_counters($fid)
|
||||
{
|
||||
global $db;
|
||||
|
||||
// Fetch the number of threads and replies in this forum (Approved only)
|
||||
$query = $db->simple_select('threads', 'COUNT(tid) AS threads, SUM(replies) AS replies, SUM(unapprovedposts) AS unapprovedposts, SUM(deletedposts) AS deletedposts', "fid='$fid' AND visible='1'");
|
||||
$count = $db->fetch_array($query);
|
||||
$count['posts'] = $count['threads'] + $count['replies'];
|
||||
|
||||
// Fetch the number of threads and replies in this forum (Unapproved only)
|
||||
$query = $db->simple_select('threads', 'COUNT(tid) AS threads, SUM(replies)+SUM(unapprovedposts)+SUM(deletedposts) AS impliedunapproved', "fid='$fid' AND visible='0'");
|
||||
$count2 = $db->fetch_array($query);
|
||||
$count['unapprovedthreads'] = $count2['threads'];
|
||||
$count['unapprovedposts'] += $count2['impliedunapproved']+$count2['threads'];
|
||||
|
||||
// Fetch the number of threads and replies in this forum (Soft deleted only)
|
||||
$query = $db->simple_select('threads', 'COUNT(tid) AS threads, SUM(replies)+SUM(unapprovedposts)+SUM(deletedposts) AS implieddeleted', "fid='$fid' AND visible='-1'");
|
||||
$count3 = $db->fetch_array($query);
|
||||
$count['deletedthreads'] = $count3['threads'];
|
||||
$count['deletedposts'] += $count3['implieddeleted']+$count3['threads'];
|
||||
|
||||
update_forum_counters($fid, $count);
|
||||
update_forum_lastpost($fid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely rebuild the counters for a particular thread (useful if they become out of sync)
|
||||
*
|
||||
* @param int $tid The thread ID
|
||||
*/
|
||||
function rebuild_thread_counters($tid)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$thread = get_thread($tid);
|
||||
$count = array();
|
||||
|
||||
$query = $db->simple_select("posts", "COUNT(pid) AS replies", "tid='{$tid}' AND pid!='{$thread['firstpost']}' AND visible='1'");
|
||||
$count['replies'] = $db->fetch_field($query, "replies");
|
||||
|
||||
// Unapproved posts
|
||||
$query = $db->simple_select("posts", "COUNT(pid) AS unapprovedposts", "tid='{$tid}' AND pid != '{$thread['firstpost']}' AND visible='0'");
|
||||
$count['unapprovedposts'] = $db->fetch_field($query, "unapprovedposts");
|
||||
|
||||
// Soft deleted posts
|
||||
$query = $db->simple_select("posts", "COUNT(pid) AS deletedposts", "tid='{$tid}' AND pid != '{$thread['firstpost']}' AND visible='-1'");
|
||||
$count['deletedposts'] = $db->fetch_field($query, "deletedposts");
|
||||
|
||||
// Attachment count
|
||||
$query = $db->query("
|
||||
SELECT COUNT(aid) AS attachment_count
|
||||
FROM ".TABLE_PREFIX."attachments a
|
||||
LEFT JOIN ".TABLE_PREFIX."posts p ON (a.pid=p.pid)
|
||||
WHERE p.tid='$tid' AND a.visible=1
|
||||
");
|
||||
$count['attachmentcount'] = $db->fetch_field($query, "attachment_count");
|
||||
|
||||
update_thread_counters($tid, $count);
|
||||
update_thread_data($tid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely rebuild poll counters for a particular poll (useful if they become out of sync)
|
||||
*
|
||||
* @param int $pid The poll ID
|
||||
*/
|
||||
function rebuild_poll_counters($pid)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$query = $db->simple_select("polls", "pid, numoptions", "pid='".(int)$pid."'");
|
||||
$poll = $db->fetch_array($query);
|
||||
|
||||
$votes = array();
|
||||
$query = $db->simple_select("pollvotes", "voteoption, COUNT(vid) AS vote_count", "pid='{$poll['pid']}'", array('group_by' => 'voteoption'));
|
||||
while($vote = $db->fetch_array($query))
|
||||
{
|
||||
$votes[$vote['voteoption']] = $vote['vote_count'];
|
||||
}
|
||||
|
||||
$voteslist = '';
|
||||
$numvotes = 0;
|
||||
for($i = 1; $i <= $poll['numoptions']; ++$i)
|
||||
{
|
||||
if(trim($voteslist != ''))
|
||||
{
|
||||
$voteslist .= "||~|~||";
|
||||
}
|
||||
|
||||
if(!isset($votes[$i]) || (int)$votes[$i] <= 0)
|
||||
{
|
||||
$votes[$i] = "0";
|
||||
}
|
||||
$voteslist .= $votes[$i];
|
||||
$numvotes = $numvotes + $votes[$i];
|
||||
}
|
||||
|
||||
$updatedpoll = array(
|
||||
"votes" => $db->escape_string($voteslist),
|
||||
"numvotes" => (int)$numvotes
|
||||
);
|
||||
$db->update_query("polls", $updatedpoll, "pid='{$poll['pid']}'");
|
||||
}
|
||||
1747
webroot/forum/inc/functions_search.php
Normal file
1747
webroot/forum/inc/functions_search.php
Normal file
File diff suppressed because it is too large
Load Diff
298
webroot/forum/inc/functions_serverstats.php
Normal file
298
webroot/forum/inc/functions_serverstats.php
Normal file
@@ -0,0 +1,298 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param int $is_install
|
||||
* @param string $prev_version
|
||||
* @param string $current_version
|
||||
* @param string $charset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function build_server_stats($is_install=1, $prev_version='', $current_version='', $charset='')
|
||||
{
|
||||
$info = array();
|
||||
|
||||
// Is this an upgrade or an install?
|
||||
if($is_install == 1)
|
||||
{
|
||||
$info['is_install'] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$info['is_install'] = 0;
|
||||
}
|
||||
|
||||
// If we are upgrading....
|
||||
if($info['is_install'] == 0)
|
||||
{
|
||||
// What was the previous version?
|
||||
$info['prev_version'] = $prev_version;
|
||||
}
|
||||
|
||||
// What's our current version?
|
||||
$info['current_version'] = $current_version;
|
||||
|
||||
// What is our current charset?
|
||||
$info['charset'] = $charset;
|
||||
|
||||
// Parse phpinfo into array
|
||||
$phpinfo = parse_php_info();
|
||||
|
||||
// PHP Version
|
||||
$info['phpversion'] = phpversion();
|
||||
|
||||
// MySQL Version
|
||||
$info['mysql'] = 0;
|
||||
if(array_key_exists('mysql', $phpinfo))
|
||||
{
|
||||
$info['mysql'] = $phpinfo['mysql']['Client API version'];
|
||||
}
|
||||
|
||||
// PostgreSQL Version
|
||||
$info['pgsql'] = 0;
|
||||
if(array_key_exists('pgsql', $phpinfo))
|
||||
{
|
||||
$info['pgsql'] = $phpinfo['pgsql']['PostgreSQL(libpq) Version'];
|
||||
}
|
||||
|
||||
// SQLite Version
|
||||
$info['sqlite'] = 0;
|
||||
if(array_key_exists('sqlite', $phpinfo))
|
||||
{
|
||||
$info['sqlite'] = $phpinfo['sqlite']['SQLite Library'];
|
||||
}
|
||||
|
||||
// Iconv Library Extension Version
|
||||
$info['iconvlib'] = 0;
|
||||
if(array_key_exists('iconv', $phpinfo))
|
||||
{
|
||||
$info['iconvlib'] = html_entity_decode($phpinfo['iconv']['iconv implementation'])."|".$phpinfo['iconv']['iconv library version'];
|
||||
}
|
||||
|
||||
// Check GD & Version
|
||||
$info['gd'] = 0;
|
||||
if(array_key_exists('gd', $phpinfo))
|
||||
{
|
||||
$info['gd'] = $phpinfo['gd']['GD Version'];
|
||||
}
|
||||
|
||||
// CGI Mode
|
||||
$sapi_type = php_sapi_name();
|
||||
|
||||
$info['cgimode'] = 0;
|
||||
if(strpos($sapi_type, 'cgi') !== false)
|
||||
{
|
||||
$info['cgimode'] = 1;
|
||||
}
|
||||
|
||||
// Server Software
|
||||
$info['server_software'] = $_SERVER['SERVER_SOFTWARE'];
|
||||
|
||||
// Allow url fopen php.ini setting
|
||||
$info['allow_url_fopen'] = 0;
|
||||
if(ini_get('safe_mode') == 0 && ini_get('allow_url_fopen'))
|
||||
{
|
||||
$info['allow_url_fopen'] = 1;
|
||||
}
|
||||
|
||||
// Check classes, extensions, php info, functions, and php ini settings
|
||||
$check = array(
|
||||
'classes' => array(
|
||||
'dom' => array('bitwise' => 1, 'title' => 'DOMElement'),
|
||||
'soap' => array('bitwise' => 2, 'title' => 'SoapClient'),
|
||||
'xmlwriter' => array('bitwise' => 4, 'title' => 'XMLWriter'),
|
||||
'imagemagick' => array('bitwise' => 8, 'title' => 'Imagick'),
|
||||
),
|
||||
|
||||
'extensions' => array(
|
||||
'zendopt' => array('bitwise' => 1, 'title' => 'Zend Optimizer'),
|
||||
'xcache' => array('bitwise' => 2, 'title' => 'XCache'),
|
||||
'eaccelerator' => array('bitwise' => 4, 'title' => 'eAccelerator'),
|
||||
'ioncube' => array('bitwise' => 8, 'title' => 'ionCube Loader'),
|
||||
'PDO' => array('bitwise' => 16, 'title' => 'PDO'),
|
||||
'pdo_mysql' => array('bitwise' => 32, 'title' => 'pdo_mysql'),
|
||||
'pdo_pgsql' => array('bitwise' => 64, 'title' => 'pdo_pgsql'),
|
||||
'pdo_sqlite' => array('bitwise' => 128, 'title' => 'pdo_sqlite'),
|
||||
'pdo_oci' => array('bitwise' => 256, 'title' => 'pdo_oci'),
|
||||
'pdo_odbc' => array('bitwise' => 512, 'title' => 'pdo_odbc'),
|
||||
),
|
||||
|
||||
'phpinfo' => array(
|
||||
'zlib' => array('bitwise' => 1, 'title' => 'zlib'),
|
||||
'mbstring' => array('bitwise' => 2, 'title' => 'mbstring'),
|
||||
'exif' => array('bitwise' => 4, 'title' => 'exif'),
|
||||
'zlib' => array('bitwise' => 8, 'title' => 'zlib'),
|
||||
|
||||
),
|
||||
|
||||
'functions' => array(
|
||||
'sockets' => array('bitwise' => 1, 'title' => 'fsockopen'),
|
||||
'mcrypt' => array('bitwise' => 2, 'title' => 'mcrypt_encrypt'),
|
||||
'simplexml' => array('bitwise' => 4, 'title' => 'simplexml_load_string'),
|
||||
'ldap' => array('bitwise' => 8, 'title' => 'ldap_connect'),
|
||||
'mysqli' => array('bitwise' => 16, 'title' => 'mysqli_connect'),
|
||||
'imap' => array('bitwise' => 32, 'title' => 'imap_open'),
|
||||
'ftp' => array('bitwise' => 64, 'title' => 'ftp_login'),
|
||||
'pspell' => array('bitwise' => 128, 'title' => 'pspell_new'),
|
||||
'apc' => array('bitwise' => 256, 'title' => 'apc_cache_info'),
|
||||
'curl' => array('bitwise' => 512, 'title' => 'curl_init'),
|
||||
'iconv' => array('bitwise' => 1024, 'title' => 'iconv'),
|
||||
),
|
||||
|
||||
'php_ini' => array(
|
||||
'post_max_size' => 'post_max_size',
|
||||
'upload_max_filesize' => 'upload_max_filesize',
|
||||
'safe_mode' => 'safe_mode',
|
||||
),
|
||||
);
|
||||
|
||||
foreach($check as $cat_name => $category)
|
||||
{
|
||||
foreach($category as $name => $what)
|
||||
{
|
||||
if(!isset($info[$cat_name]))
|
||||
{
|
||||
$info[$cat_name] = 0;
|
||||
}
|
||||
switch($cat_name)
|
||||
{
|
||||
case "classes":
|
||||
if(class_exists($what['title']))
|
||||
{
|
||||
$info[$cat_name] |= $what['bitwise'];
|
||||
}
|
||||
break;
|
||||
case "extensions":
|
||||
if(extension_loaded($what['title']))
|
||||
{
|
||||
$info[$cat_name] |= $what['bitwise'];
|
||||
}
|
||||
break;
|
||||
case "phpinfo":
|
||||
if(array_key_exists($what['title'], $phpinfo))
|
||||
{
|
||||
$info[$cat_name] |= $what['bitwise'];
|
||||
}
|
||||
break;
|
||||
case "functions":
|
||||
if(function_exists($what['title']))
|
||||
{
|
||||
$info[$cat_name] |= $what['bitwise'];
|
||||
}
|
||||
break;
|
||||
case "php_ini":
|
||||
if(ini_get($what) != 0)
|
||||
{
|
||||
$info[$name] = ini_get($what);
|
||||
}
|
||||
else
|
||||
{
|
||||
$info[$name] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Host URL & hostname
|
||||
// Dropped fetching host details since v.1.8.16 as http://www.whoishostingthis.com API seems to be down and this info is not required by MyBB.
|
||||
$info['hosturl'] = $info['hostname'] = "unknown/local";
|
||||
if($_SERVER['HTTP_HOST'] == 'localhost')
|
||||
{
|
||||
$info['hosturl'] = $info['hostname'] = "localhost";
|
||||
}
|
||||
|
||||
if(isset($_SERVER['HTTP_USER_AGENT']))
|
||||
{
|
||||
$info['useragent'] = $_SERVER['HTTP_USER_AGENT'];
|
||||
}
|
||||
|
||||
// We need a unique ID for the host so hash it to keep it private and send it over
|
||||
$id = $_SERVER['HTTP_HOST'].time();
|
||||
|
||||
if(function_exists('sha1'))
|
||||
{
|
||||
$info['clientid'] = sha1($id);
|
||||
}
|
||||
else
|
||||
{
|
||||
$info['clientid'] = md5($id);
|
||||
}
|
||||
|
||||
$string = "";
|
||||
$amp = "";
|
||||
foreach($info as $key => $value)
|
||||
{
|
||||
$string .= $amp.$key."=".urlencode($value);
|
||||
$amp = "&";
|
||||
}
|
||||
|
||||
$server_stats_url = 'https://community.mybb.com/server_stats.php?'.$string;
|
||||
|
||||
$return = array();
|
||||
$return['info_sent_success'] = false;
|
||||
if(fetch_remote_file($server_stats_url) !== false)
|
||||
{
|
||||
$return['info_sent_success'] = true;
|
||||
}
|
||||
$return['info_image'] = "<img src='".$server_stats_url."&img=1' />";
|
||||
$return['info_get_string'] = $string;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* parser_php_info
|
||||
* Function to get and parse the list of PHP info into a usuable array
|
||||
*
|
||||
* @return Array An array of all the extensions installed in PHP
|
||||
*/
|
||||
function parse_php_info()
|
||||
{
|
||||
ob_start();
|
||||
phpinfo(INFO_MODULES);
|
||||
$phpinfo_html = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
$phpinfo_html = strip_tags($phpinfo_html, "<h2><th><td>");
|
||||
$phpinfo_html = preg_replace("#<th[^>]*>([^<]+)<\/th>#", "<info>$1</info>", $phpinfo_html);
|
||||
$phpinfo_html = preg_replace("#<td[^>]*>([^<]+)<\/td>#", "<info>$1</info>", $phpinfo_html);
|
||||
$phpinfo_html = preg_split("#(<h2[^>]*>[^<]+<\/h2>)#", $phpinfo_html, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$modules = array();
|
||||
|
||||
for($i=1; $i < count($phpinfo_html); $i++)
|
||||
{
|
||||
if(preg_match("#<h2[^>]*>([^<]+)<\/h2>#", $phpinfo_html[$i], $match))
|
||||
{
|
||||
$name = trim($match[1]);
|
||||
$tmp2 = explode("\n", $phpinfo_html[$i+1]);
|
||||
foreach($tmp2 as $one)
|
||||
{
|
||||
$pat = '<info>([^<]+)<\/info>';
|
||||
$pat3 = "/$pat\s*$pat\s*$pat/";
|
||||
$pat2 = "/$pat\s*$pat/";
|
||||
|
||||
// 3 columns
|
||||
if(preg_match($pat3, $one, $match))
|
||||
{
|
||||
$modules[$name][trim($match[1])] = array(trim($match[2]), trim($match[3]));
|
||||
}
|
||||
// 2 columns
|
||||
else if(preg_match($pat2, $one, $match))
|
||||
{
|
||||
$modules[$name][trim($match[1])] = trim($match[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $modules;
|
||||
}
|
||||
|
||||
385
webroot/forum/inc/functions_task.php
Normal file
385
webroot/forum/inc/functions_task.php
Normal file
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Execute a scheduled task.
|
||||
*
|
||||
* @param int $tid The task ID. If none specified, the next task due to be ran is executed
|
||||
* @return boolean True if successful, false on failure
|
||||
*/
|
||||
function run_task($tid=0)
|
||||
{
|
||||
global $db, $mybb, $cache, $plugins, $task, $lang;
|
||||
|
||||
// Run a specific task
|
||||
if($tid > 0)
|
||||
{
|
||||
$query = $db->simple_select("tasks", "*", "tid='{$tid}'");
|
||||
$task = $db->fetch_array($query);
|
||||
}
|
||||
|
||||
// Run the next task due to be run
|
||||
else
|
||||
{
|
||||
$query = $db->simple_select("tasks", "*", "enabled=1 AND nextrun<='".TIME_NOW."'", array("order_by" => "nextrun", "order_dir" => "asc", "limit" => 1));
|
||||
$task = $db->fetch_array($query);
|
||||
}
|
||||
|
||||
// No task? Return
|
||||
if(!$task['tid'])
|
||||
{
|
||||
$cache->update_tasks();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this task still running and locked less than 5 minutes ago? Well don't run it now - clearly it isn't broken!
|
||||
if($task['locked'] != 0 && $task['locked'] > TIME_NOW-300)
|
||||
{
|
||||
$cache->update_tasks();
|
||||
return false;
|
||||
}
|
||||
// Lock it! It' mine, all mine!
|
||||
else
|
||||
{
|
||||
$db->update_query("tasks", array("locked" => TIME_NOW), "tid='{$task['tid']}'");
|
||||
}
|
||||
|
||||
$file = basename($task['file'], '.php');
|
||||
|
||||
// The task file does not exist
|
||||
if(!file_exists(MYBB_ROOT."inc/tasks/{$file}.php"))
|
||||
{
|
||||
if($task['logging'] == 1)
|
||||
{
|
||||
add_task_log($task, $lang->missing_task);
|
||||
}
|
||||
|
||||
// If task file does not exist, disable task and inform the administrator
|
||||
$updated_task = array(
|
||||
"enabled" => 0,
|
||||
"locked" => 0
|
||||
);
|
||||
$db->update_query("tasks", $updated_task, "tid='{$task['tid']}'");
|
||||
|
||||
$subject = $lang->sprintf($lang->email_broken_task_subject, $mybb->settings['bbname']);
|
||||
$message = $lang->sprintf($lang->email_broken_task, $mybb->settings['bbname'], $mybb->settings['bburl'], $task['title']);
|
||||
|
||||
my_mail($mybb->settings['adminemail'], $subject, $message, $mybb->settings['adminemail']);
|
||||
|
||||
$cache->update_tasks();
|
||||
return false;
|
||||
}
|
||||
// Run the task
|
||||
else
|
||||
{
|
||||
// Update the nextrun time now, so if the task causes a fatal error, it doesn't get stuck first in the queue
|
||||
$nextrun = fetch_next_run($task);
|
||||
$db->update_query("tasks", array("nextrun" => $nextrun), "tid='{$task['tid']}'");
|
||||
|
||||
include_once MYBB_ROOT."inc/tasks/{$file}.php";
|
||||
$function = "task_{$task['file']}";
|
||||
if(function_exists($function))
|
||||
{
|
||||
$function($task);
|
||||
}
|
||||
}
|
||||
|
||||
$updated_task = array(
|
||||
"lastrun" => TIME_NOW,
|
||||
"locked" => 0
|
||||
);
|
||||
$db->update_query("tasks", $updated_task, "tid='{$task['tid']}'");
|
||||
|
||||
$cache->update_tasks();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds information to the scheduled task log.
|
||||
*
|
||||
* @param int $task The task array to create the log entry for
|
||||
* @param string $message The message to log
|
||||
*/
|
||||
function add_task_log($task, $message)
|
||||
{
|
||||
global $db;
|
||||
|
||||
if(!$task['logging'])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$log_entry = array(
|
||||
"tid" => (int)$task['tid'],
|
||||
"dateline" => TIME_NOW,
|
||||
"data" => $db->escape_string($message)
|
||||
);
|
||||
$db->insert_query("tasklog", $log_entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the next run time for a particular task.
|
||||
*
|
||||
* @param array $task The task array as fetched from the database.
|
||||
* @return int The next run time as a UNIX timestamp
|
||||
*/
|
||||
function fetch_next_run($task)
|
||||
{
|
||||
$time = TIME_NOW;
|
||||
$next_minute = $current_minute = date("i", $time);
|
||||
$next_hour = $current_hour = date("H", $time);
|
||||
$next_day = $current_day = date("d", $time);
|
||||
$next_weekday = $current_weekday = date("w", $time);
|
||||
$next_month = $current_month = date("m", $time);
|
||||
$next_year = $current_year = date("Y", $time);
|
||||
$reset_day = $reset_hour = $reset_month = $reset_year = 0;
|
||||
|
||||
if($task['minute'] == "*")
|
||||
{
|
||||
++$next_minute;
|
||||
if($next_minute > 59)
|
||||
{
|
||||
$reset_hour = 1;
|
||||
$next_minute = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(build_next_run_bit($task['minute'], $current_minute) != false)
|
||||
{
|
||||
$next_minute = build_next_run_bit($task['minute'], $current_minute);
|
||||
}
|
||||
else
|
||||
{
|
||||
$next_minute = fetch_first_run_time($task['minute']);
|
||||
}
|
||||
if($next_minute <= $current_minute)
|
||||
{
|
||||
$reset_hour = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if($reset_hour || !run_time_exists($task['hour'], $current_hour))
|
||||
{
|
||||
if($task['hour'] == "*")
|
||||
{
|
||||
++$next_hour;
|
||||
if($next_hour > 23)
|
||||
{
|
||||
$reset_day = 1;
|
||||
$next_hour = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(build_next_run_bit($task['hour'], $current_hour) != false)
|
||||
{
|
||||
$next_hour = build_next_run_bit($task['hour'], $current_hour);
|
||||
}
|
||||
else
|
||||
{
|
||||
$next_hour = fetch_first_run_time($task['hour']);
|
||||
$reset_day = 1;
|
||||
}
|
||||
if($next_hour < $current_hour)
|
||||
{
|
||||
$reset_day = 1;
|
||||
}
|
||||
}
|
||||
$next_minute = fetch_first_run_time($task['minute']);
|
||||
}
|
||||
|
||||
if($reset_day || ($task['weekday'] == "*" && !run_time_exists($task['day'], $current_day) || $task['day'] == "*" && !run_time_exists($task['weekday'], $current_weekday)))
|
||||
{
|
||||
if($task['weekday'] == "*")
|
||||
{
|
||||
if($task['day'] == "*")
|
||||
{
|
||||
++$next_day;
|
||||
if($next_day > date("t", $time))
|
||||
{
|
||||
$reset_month = 1;
|
||||
$next_day = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(build_next_run_bit($task['day'], $current_day) != false)
|
||||
{
|
||||
$next_day = build_next_run_bit($task['day'], $current_day);
|
||||
}
|
||||
else
|
||||
{
|
||||
$next_day = fetch_first_run_time($task['day']);
|
||||
$reset_month = 1;
|
||||
}
|
||||
if($next_day < $current_day)
|
||||
{
|
||||
$reset_month = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(build_next_run_bit($task['weekday'], $current_weekday) != false)
|
||||
{
|
||||
$next_weekday = build_next_run_bit($task['weekday'], $current_weekday);
|
||||
}
|
||||
else
|
||||
{
|
||||
$next_weekday = fetch_first_run_time($task['weekday']);
|
||||
}
|
||||
$next_day = $current_day + ($next_weekday-$current_weekday);
|
||||
if($next_day <= $current_day)
|
||||
{
|
||||
$next_day += 7;
|
||||
}
|
||||
|
||||
if($next_day > date("t", $time))
|
||||
{
|
||||
$reset_month = 1;
|
||||
}
|
||||
}
|
||||
$next_minute = fetch_first_run_time($task['minute']);
|
||||
$next_hour = fetch_first_run_time($task['hour']);
|
||||
if($next_day == $current_day && $next_hour < $current_hour)
|
||||
{
|
||||
$reset_month = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if($reset_month || !run_time_exists($task['month'], $current_month))
|
||||
{
|
||||
if($task['month'] == "*")
|
||||
{
|
||||
$next_month++;
|
||||
if($next_month > 12)
|
||||
{
|
||||
$reset_year = 1;
|
||||
$next_month = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(build_next_run_bit($task['month'], $current_month) != false)
|
||||
{
|
||||
$next_month = build_next_run_bit($task['month'], $current_month);
|
||||
}
|
||||
else
|
||||
{
|
||||
$next_month = fetch_first_run_time($task['month']);
|
||||
$reset_year = 1;
|
||||
}
|
||||
if($next_month < $current_month)
|
||||
{
|
||||
$reset_year = 1;
|
||||
}
|
||||
}
|
||||
$next_minute = fetch_first_run_time($task['minute']);
|
||||
$next_hour = fetch_first_run_time($task['hour']);
|
||||
if($task['weekday'] == "*")
|
||||
{
|
||||
$next_day = fetch_first_run_time($task['day']);
|
||||
if($next_day == 0) $next_day = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$next_weekday = fetch_first_run_time($task['weekday']);
|
||||
$new_weekday = date("w", mktime($next_hour, $next_minute, 0, $next_month, 1, $next_year));
|
||||
$next_day = 1 + ($next_weekday-$new_weekday);
|
||||
if($next_weekday < $new_weekday)
|
||||
{
|
||||
$next_day += 7;
|
||||
}
|
||||
}
|
||||
if($next_month == $current_month && $next_day == $current_day && $next_hour < $current_hour)
|
||||
{
|
||||
$reset_year = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if($reset_year)
|
||||
{
|
||||
$next_year++;
|
||||
$next_minute = fetch_first_run_time($task['minute']);
|
||||
$next_hour = fetch_first_run_time($task['hour']);
|
||||
$next_month = fetch_first_run_time($task['month']);
|
||||
if($next_month == 0) $next_month = 1;
|
||||
if($task['weekday'] == "*")
|
||||
{
|
||||
$next_day = fetch_first_run_time($task['day']);
|
||||
if($next_day == 0) $next_day = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$next_weekday = fetch_first_run_time($task['weekday']);
|
||||
$new_weekday = date("w", mktime($next_hour, $next_minute, 0, $next_month, 1, $next_year));
|
||||
$next_day = 1 + ($next_weekday-$new_weekday);
|
||||
if($next_weekday < $new_weekday)
|
||||
{
|
||||
$next_day += 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mktime($next_hour, $next_minute, 0, $next_month, $next_day, $next_year);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the next run time bit for a particular item (day, hour, month etc). Used by fetch_next_run().
|
||||
*
|
||||
* @param string $data A string containing the run times for this particular item
|
||||
* @param int $bit The current value (be it current day etc)
|
||||
* @return int|bool The new or found value or boolean if nothing is found
|
||||
*/
|
||||
function build_next_run_bit($data, $bit)
|
||||
{
|
||||
if($data == "*") return $bit;
|
||||
$data = explode(",", $data);
|
||||
foreach($data as $thing)
|
||||
{
|
||||
if($thing > $bit)
|
||||
{
|
||||
return $thing;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the fist run bit for a particular item (day, hour, month etc). Used by fetch_next_run().
|
||||
*
|
||||
* @param string $data A string containing the run times for this particular item
|
||||
* @return int The first run time
|
||||
*/
|
||||
function fetch_first_run_time($data)
|
||||
{
|
||||
if($data == "*") return "0";
|
||||
$data = explode(",", $data);
|
||||
return $data[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a specific run time exists for a particular item (day, hour, month etc). Used by fetch_next_run().
|
||||
*
|
||||
* @param string $data A string containing the run times for this particular item
|
||||
* @param int $bit The bit we're checking for
|
||||
* @return boolean True if it exists, false if it does not
|
||||
*/
|
||||
function run_time_exists($data, $bit)
|
||||
{
|
||||
if($data == "*") return true;
|
||||
$data = explode(",", $data);
|
||||
if(in_array($bit, $data))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
877
webroot/forum/inc/functions_time.php
Normal file
877
webroot/forum/inc/functions_time.php
Normal file
@@ -0,0 +1,877 @@
|
||||
<?php
|
||||
/** This file is distributed with MyBB under the BSD License package and modified to work with MyBB **/
|
||||
|
||||
/**
|
||||
ADOdb Date Library, part of the ADOdb abstraction library
|
||||
Download: http://phplens.com/phpeverywhere/
|
||||
|
||||
PHP native date functions use integer timestamps for computations.
|
||||
Because of this, dates are restricted to the years 1901-2038 on Unix
|
||||
and 1970-2038 on Windows due to integer overflow for dates beyond
|
||||
those years. This library overcomes these limitations by replacing the
|
||||
native function's signed integers (normally 32-bits) with PHP floating
|
||||
point numbers (normally 64-bits).
|
||||
|
||||
Dates from 100 A.D. to 3000 A.D. and later
|
||||
have been tested. The minimum is 100 A.D. as <100 will invoke the
|
||||
2 => 4 digit year conversion. The maximum is billions of years in the
|
||||
future, but this is a theoretical limit as the computation of that year
|
||||
would take too long with the current implementation of adodb_mktime().
|
||||
|
||||
This library replaces native functions as follows:
|
||||
|
||||
<pre>
|
||||
getdate() with adodb_getdate()
|
||||
date() with adodb_date()
|
||||
gmdate() with adodb_gmdate()
|
||||
mktime() with adodb_mktime()
|
||||
gmmktime() with adodb_gmmktime()
|
||||
strftime() with adodb_strftime()
|
||||
strftime() with adodb_gmstrftime()
|
||||
</pre>
|
||||
|
||||
The parameters are identical, except that adodb_date() accepts a subset
|
||||
of date()'s field formats. Mktime() will convert from local time to GMT,
|
||||
and date() will convert from GMT to local time, but daylight savings is
|
||||
not handled currently.
|
||||
|
||||
This library is independant of the rest of ADOdb, and can be used
|
||||
as standalone code.
|
||||
|
||||
PERFORMANCE
|
||||
|
||||
For high speed, this library uses the native date functions where
|
||||
possible, and only switches to PHP code when the dates fall outside
|
||||
the 32-bit signed integer range.
|
||||
|
||||
GREGORIAN CORRECTION
|
||||
|
||||
Pope Gregory shortened October of A.D. 1582 by ten days. Thursday,
|
||||
October 4, 1582 (Julian) was followed immediately by Friday, October 15,
|
||||
1582 (Gregorian).
|
||||
|
||||
Since 0.06, we handle this correctly, so:
|
||||
|
||||
adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582)
|
||||
== 24 * 3600 (1 day)
|
||||
|
||||
=============================================================================
|
||||
|
||||
COPYRIGHT
|
||||
|
||||
(c) 2003-2005 John Lim and released under BSD-style license except for code by
|
||||
jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year
|
||||
and originally found at http://www.php.net/manual/en/function.mktime.php
|
||||
|
||||
=============================================================================
|
||||
|
||||
BUG REPORTS
|
||||
|
||||
These should be posted to the ADOdb forums at
|
||||
|
||||
http://phplens.com/lens/lensforum/topics.php?id=4
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/* Initialization */
|
||||
|
||||
/*
|
||||
Version Number
|
||||
*/
|
||||
define('ADODB_DATE_VERSION', 0.33);
|
||||
|
||||
$ADODB_DATETIME_CLASS = (PHP_VERSION >= 5.2);
|
||||
|
||||
/*
|
||||
This code was originally for windows. But apparently this problem happens
|
||||
also with Linux, RH 7.3 and later!
|
||||
|
||||
glibc-2.2.5-34 and greater has been changed to return -1 for dates <
|
||||
1970. This used to work. The problem exists with RedHat 7.3 and 8.0
|
||||
echo (mktime(0, 0, 0, 1, 1, 1960)); // prints -1
|
||||
|
||||
References:
|
||||
http://bugs.php.net/bug.php?id=20048&edit=2
|
||||
http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html
|
||||
*/
|
||||
|
||||
if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);
|
||||
|
||||
/**
|
||||
Returns day of week, 0 = Sunday,... 6=Saturday.
|
||||
Algorithm from PEAR::Date_Calc
|
||||
*/
|
||||
function adodb_dow($year, $month, $day)
|
||||
{
|
||||
/*
|
||||
Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and
|
||||
proclaimed that from that time onwards 3 days would be dropped from the calendar
|
||||
every 400 years.
|
||||
|
||||
Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian).
|
||||
*/
|
||||
if ($year <= 1582) {
|
||||
if ($year < 1582 ||
|
||||
($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3;
|
||||
else
|
||||
$greg_correction = 0;
|
||||
} else
|
||||
$greg_correction = 0;
|
||||
|
||||
if($month > 2)
|
||||
$month -= 2;
|
||||
else {
|
||||
$month += 10;
|
||||
$year--;
|
||||
}
|
||||
|
||||
$day = floor((13 * $month - 1) / 5) +
|
||||
$day + ($year % 100) +
|
||||
floor(($year % 100) / 4) +
|
||||
floor(($year / 100) / 4) - 2 *
|
||||
floor($year / 100) + 77 + $greg_correction;
|
||||
|
||||
return $day - 7 * floor($day / 7);
|
||||
}
|
||||
|
||||
/**
|
||||
Checks for leap year, returns true if it is. No 2-digit year check. Also
|
||||
handles julian calendar correctly.
|
||||
*/
|
||||
function _adodb_is_leap_year($year)
|
||||
{
|
||||
if ($year % 4 != 0) return false;
|
||||
|
||||
if ($year % 400 == 0) {
|
||||
return true;
|
||||
// if gregorian calendar (>1582), century not-divisible by 400 is not leap
|
||||
} else if ($year > 1582 && $year % 100 == 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
checks for leap year, returns true if it is. Has 2-digit year check
|
||||
*/
|
||||
function adodb_is_leap_year($year)
|
||||
{
|
||||
return _adodb_is_leap_year(adodb_year_digit_check($year));
|
||||
}
|
||||
|
||||
/**
|
||||
Fix 2-digit years. Works for any century.
|
||||
Assumes that if 2-digit is more than 30 years in future, then previous century.
|
||||
*/
|
||||
function adodb_year_digit_check($y)
|
||||
{
|
||||
if ($y < 100) {
|
||||
|
||||
$yr = (integer) date("Y");
|
||||
$century = (integer) ($yr /100);
|
||||
|
||||
if ($yr%100 > 50) {
|
||||
$c1 = $century + 1;
|
||||
$c0 = $century;
|
||||
} else {
|
||||
$c1 = $century;
|
||||
$c0 = $century - 1;
|
||||
}
|
||||
$c1 *= 100;
|
||||
// if 2-digit year is less than 30 years in future, set it to this century
|
||||
// otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
|
||||
if (($y + $c1) < $yr+30) $y = $y + $c1;
|
||||
else $y = $y + $c0*100;
|
||||
}
|
||||
return $y;
|
||||
}
|
||||
|
||||
function adodb_get_gmt_diff_ts($ts)
|
||||
{
|
||||
if (0 <= $ts && $ts <= 0x7FFFFFFF) { // check if number in 32-bit signed range) {
|
||||
$arr = getdate($ts);
|
||||
$y = $arr['year'];
|
||||
$m = $arr['mon'];
|
||||
$d = $arr['mday'];
|
||||
return adodb_get_gmt_diff($y,$m,$d);
|
||||
} else {
|
||||
return adodb_get_gmt_diff(false,false,false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
get local time zone offset from GMT. Does not handle historical timezones before 1970.
|
||||
*/
|
||||
function adodb_get_gmt_diff($y,$m,$d)
|
||||
{
|
||||
static $TZ,$tzo;
|
||||
global $ADODB_DATETIME_CLASS;
|
||||
|
||||
if (!defined('ADODB_TEST_DATES')) $y = false;
|
||||
else if ($y < 1970 || $y >= 2038) $y = false;
|
||||
|
||||
if ($ADODB_DATETIME_CLASS && $y !== false) {
|
||||
$dt = new DateTime();
|
||||
$dt->setISODate($y,$m,$d);
|
||||
if (empty($tzo)) {
|
||||
$tzo = new DateTimeZone(date_default_timezone_get());
|
||||
# $tzt = timezone_transitions_get( $tzo );
|
||||
}
|
||||
return -$tzo->getOffset($dt);
|
||||
} else {
|
||||
if (isset($TZ)) return $TZ;
|
||||
$y = date('Y');
|
||||
$TZ = mktime(0,0,0,12,2,$y) - gmmktime(0,0,0,12,2,$y);
|
||||
}
|
||||
|
||||
return $TZ;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an array with date info.
|
||||
*/
|
||||
function adodb_getdate($d=false,$fast=false)
|
||||
{
|
||||
if ($d === false) return getdate();
|
||||
if (!defined('ADODB_TEST_DATES')) {
|
||||
if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
|
||||
if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
|
||||
return @getdate($d);
|
||||
}
|
||||
}
|
||||
return _adodb_getdate($d);
|
||||
}
|
||||
|
||||
$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
|
||||
$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
|
||||
|
||||
/**
|
||||
Low-level function that returns the getdate() array. We have a special
|
||||
$fast flag, which if set to true, will return fewer array values,
|
||||
and is much faster as it does not calculate dow, etc.
|
||||
*/
|
||||
function _adodb_getdate($origd=false,$fast=false,$is_gmt=false)
|
||||
{
|
||||
static $YRS;
|
||||
global $_month_table_normal,$_month_table_leaf;
|
||||
|
||||
$d = $origd - ($is_gmt ? 0 : adodb_get_gmt_diff_ts($origd));
|
||||
$_day_power = 86400;
|
||||
$_hour_power = 3600;
|
||||
$_min_power = 60;
|
||||
|
||||
if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction
|
||||
|
||||
$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
|
||||
$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
|
||||
|
||||
$d366 = $_day_power * 366;
|
||||
$d365 = $_day_power * 365;
|
||||
|
||||
if ($d < 0) {
|
||||
|
||||
if (empty($YRS)) $YRS = array(
|
||||
1970 => 0,
|
||||
1960 => -315619200,
|
||||
1950 => -631152000,
|
||||
1940 => -946771200,
|
||||
1930 => -1262304000,
|
||||
1920 => -1577923200,
|
||||
1910 => -1893456000,
|
||||
1900 => -2208988800,
|
||||
1890 => -2524521600,
|
||||
1880 => -2840140800,
|
||||
1870 => -3155673600,
|
||||
1860 => -3471292800,
|
||||
1850 => -3786825600,
|
||||
1840 => -4102444800,
|
||||
1830 => -4417977600,
|
||||
1820 => -4733596800,
|
||||
1810 => -5049129600,
|
||||
1800 => -5364662400,
|
||||
1790 => -5680195200,
|
||||
1780 => -5995814400,
|
||||
1770 => -6311347200,
|
||||
1760 => -6626966400,
|
||||
1750 => -6942499200,
|
||||
1740 => -7258118400,
|
||||
1730 => -7573651200,
|
||||
1720 => -7889270400,
|
||||
1710 => -8204803200,
|
||||
1700 => -8520336000,
|
||||
1690 => -8835868800,
|
||||
1680 => -9151488000,
|
||||
1670 => -9467020800,
|
||||
1660 => -9782640000,
|
||||
1650 => -10098172800,
|
||||
1640 => -10413792000,
|
||||
1630 => -10729324800,
|
||||
1620 => -11044944000,
|
||||
1610 => -11360476800,
|
||||
1600 => -11676096000);
|
||||
|
||||
if ($is_gmt) $origd = $d;
|
||||
// The valid range of a 32bit signed timestamp is typically from
|
||||
// Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT
|
||||
//
|
||||
|
||||
# old algorithm iterates through all years. new algorithm does it in
|
||||
# 10 year blocks
|
||||
|
||||
/*
|
||||
# old algo
|
||||
for ($a = 1970 ; --$a >= 0;) {
|
||||
$lastd = $d;
|
||||
|
||||
if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
|
||||
else $d += $d365;
|
||||
|
||||
if ($d >= 0) {
|
||||
$year = $a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
$lastsecs = 0;
|
||||
$lastyear = 1970;
|
||||
foreach($YRS as $year => $secs) {
|
||||
if ($d >= $secs) {
|
||||
$a = $lastyear;
|
||||
break;
|
||||
}
|
||||
$lastsecs = $secs;
|
||||
$lastyear = $year;
|
||||
}
|
||||
|
||||
$d -= $lastsecs;
|
||||
if (!isset($a)) $a = $lastyear;
|
||||
|
||||
//echo ' yr=',$a,' ', $d,'.';
|
||||
|
||||
for (; --$a >= 0;) {
|
||||
$lastd = $d;
|
||||
|
||||
if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
|
||||
else $d += $d365;
|
||||
|
||||
if ($d >= 0) {
|
||||
$year = $a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**/
|
||||
|
||||
$secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;
|
||||
|
||||
$d = $lastd;
|
||||
$mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
|
||||
for ($a = 13 ; --$a > 0;) {
|
||||
$lastd = $d;
|
||||
$d += $mtab[$a] * $_day_power;
|
||||
if ($d >= 0) {
|
||||
$month = $a;
|
||||
$ndays = $mtab[$a];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$d = $lastd;
|
||||
$day = $ndays + ceil(($d+1) / ($_day_power));
|
||||
|
||||
$d += ($ndays - $day+1)* $_day_power;
|
||||
$hour = floor($d/$_hour_power);
|
||||
|
||||
} else {
|
||||
for ($a = 1970 ;; $a++) {
|
||||
$lastd = $d;
|
||||
|
||||
if ($leaf = _adodb_is_leap_year($a)) $d -= $d366;
|
||||
else $d -= $d365;
|
||||
if ($d < 0) {
|
||||
$year = $a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$secsInYear = $lastd;
|
||||
$d = $lastd;
|
||||
$mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
|
||||
for ($a = 1 ; $a <= 12; $a++) {
|
||||
$lastd = $d;
|
||||
$d -= $mtab[$a] * $_day_power;
|
||||
if ($d < 0) {
|
||||
$month = $a;
|
||||
$ndays = $mtab[$a];
|
||||
break;
|
||||
}
|
||||
}
|
||||
$d = $lastd;
|
||||
$day = ceil(($d+1) / $_day_power);
|
||||
$d = $d - ($day-1) * $_day_power;
|
||||
$hour = floor($d /$_hour_power);
|
||||
}
|
||||
|
||||
$d -= $hour * $_hour_power;
|
||||
$min = floor($d/$_min_power);
|
||||
$secs = $d - $min * $_min_power;
|
||||
if ($fast) {
|
||||
return array(
|
||||
'seconds' => $secs,
|
||||
'minutes' => $min,
|
||||
'hours' => $hour,
|
||||
'mday' => $day,
|
||||
'mon' => $month,
|
||||
'year' => $year,
|
||||
'yday' => floor($secsInYear/$_day_power),
|
||||
'leap' => $leaf,
|
||||
'ndays' => $ndays
|
||||
);
|
||||
}
|
||||
|
||||
$dow = adodb_dow($year,$month,$day);
|
||||
|
||||
return array(
|
||||
'seconds' => $secs,
|
||||
'minutes' => $min,
|
||||
'hours' => $hour,
|
||||
'mday' => $day,
|
||||
'wday' => $dow,
|
||||
'mon' => $month,
|
||||
'year' => $year,
|
||||
'yday' => floor($secsInYear/$_day_power),
|
||||
'weekday' => gmdate('l',$_day_power*(3+$dow)),
|
||||
'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),
|
||||
0 => $origd
|
||||
);
|
||||
}
|
||||
|
||||
function adodb_tz_offset($gmt,$isphp5)
|
||||
{
|
||||
$zhrs = abs($gmt)/3600;
|
||||
$hrs = floor($zhrs);
|
||||
if ($isphp5)
|
||||
return sprintf('%s%02d%02d',($gmt<=0)?'+':'-',floor($zhrs),($zhrs-$hrs)*60);
|
||||
else
|
||||
return sprintf('%s%02d%02d',($gmt<0)?'+':'-',floor($zhrs),($zhrs-$hrs)*60);
|
||||
}
|
||||
|
||||
function adodb_gmdate($fmt,$d=false)
|
||||
{
|
||||
return adodb_date($fmt,$d,true);
|
||||
}
|
||||
|
||||
// accepts unix timestamp and iso date format in $d
|
||||
function adodb_date2($fmt, $d=false, $is_gmt=false)
|
||||
{
|
||||
if ($d !== false) {
|
||||
if (!preg_match(
|
||||
"|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
|
||||
($d), $rr)) return adodb_date($fmt,false,$is_gmt);
|
||||
|
||||
if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt);
|
||||
|
||||
// h-m-s-MM-DD-YY
|
||||
if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1],false,$is_gmt);
|
||||
else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1],false,$is_gmt);
|
||||
}
|
||||
|
||||
return adodb_date($fmt,$d,$is_gmt);
|
||||
}
|
||||
|
||||
/**
|
||||
Return formatted date based on timestamp $d
|
||||
*/
|
||||
function adodb_date($fmt,$d=false,$is_gmt=false)
|
||||
{
|
||||
static $daylight;
|
||||
global $ADODB_DATETIME_CLASS;
|
||||
|
||||
if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt);
|
||||
if (!defined('ADODB_TEST_DATES')) {
|
||||
if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
|
||||
if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
|
||||
return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d);
|
||||
|
||||
}
|
||||
}
|
||||
$_day_power = 86400;
|
||||
|
||||
$arr = _adodb_getdate($d,true,$is_gmt);
|
||||
|
||||
if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv');
|
||||
if ($daylight) adodb_daylight_sv($arr, $is_gmt);
|
||||
|
||||
$year = $arr['year'];
|
||||
$month = $arr['mon'];
|
||||
$day = $arr['mday'];
|
||||
$hour = $arr['hours'];
|
||||
$min = $arr['minutes'];
|
||||
$secs = $arr['seconds'];
|
||||
|
||||
$max = strlen($fmt);
|
||||
$dates = '';
|
||||
|
||||
$isphp5 = PHP_VERSION >= 5;
|
||||
|
||||
/*
|
||||
at this point, we have the following integer vars to manipulate:
|
||||
$year, $month, $day, $hour, $min, $secs
|
||||
*/
|
||||
for ($i=0; $i < $max; $i++) {
|
||||
switch($fmt[$i]) {
|
||||
case 'T':
|
||||
if ($ADODB_DATETIME_CLASS) {
|
||||
$dt = new DateTime();
|
||||
$dt->SetDate($year,$month,$day);
|
||||
$dates .= $dt->Format('T');
|
||||
} else
|
||||
$dates .= date('T');
|
||||
break;
|
||||
// YEAR
|
||||
case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
|
||||
case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
|
||||
|
||||
// 4.3.11 uses '04 Jun 2004'
|
||||
// 4.3.8 uses ' 4 Jun 2004'
|
||||
$dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', '
|
||||
. ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
|
||||
|
||||
if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour;
|
||||
|
||||
if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min;
|
||||
|
||||
if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;
|
||||
|
||||
$gmt = adodb_get_gmt_diff($year,$month,$day);
|
||||
|
||||
$dates .= ' '.adodb_tz_offset($gmt,$isphp5);
|
||||
break;
|
||||
|
||||
case 'Y': $dates .= $year; break;
|
||||
case 'y': $dates .= substr($year,strlen($year)-2,2); break;
|
||||
// MONTH
|
||||
case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;
|
||||
case 'Q': $dates .= ($month+3)>>2; break;
|
||||
case 'n': $dates .= $month; break;
|
||||
case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;
|
||||
case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;
|
||||
// DAY
|
||||
case 't': $dates .= $arr['ndays']; break;
|
||||
case 'z': $dates .= $arr['yday']; break;
|
||||
case 'w': $dates .= adodb_dow($year,$month,$day); break;
|
||||
case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break;
|
||||
case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break;
|
||||
case 'j': $dates .= $day; break;
|
||||
case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break;
|
||||
case 'S':
|
||||
$d10 = $day % 10;
|
||||
if ($d10 == 1) $dates .= 'st';
|
||||
else if ($d10 == 2 && $day != 12) $dates .= 'nd';
|
||||
else if ($d10 == 3) $dates .= 'rd';
|
||||
else $dates .= 'th';
|
||||
break;
|
||||
|
||||
// HOUR
|
||||
case 'Z':
|
||||
$dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff($year,$month,$day); break;
|
||||
case 'O':
|
||||
$gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff($year,$month,$day);
|
||||
|
||||
$dates .= adodb_tz_offset($gmt,$isphp5);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
if ($hour < 10) $dates .= '0'.$hour;
|
||||
else $dates .= $hour;
|
||||
break;
|
||||
case 'h':
|
||||
if ($hour > 12) $hh = $hour - 12;
|
||||
else {
|
||||
if ($hour == 0) $hh = '12';
|
||||
else $hh = $hour;
|
||||
}
|
||||
|
||||
if ($hh < 10) $dates .= '0'.$hh;
|
||||
else $dates .= $hh;
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
$dates .= $hour;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
if ($hour > 12) $hh = $hour - 12;
|
||||
else {
|
||||
if ($hour == 0) $hh = '12';
|
||||
else $hh = $hour;
|
||||
}
|
||||
$dates .= $hh;
|
||||
break;
|
||||
// MINUTES
|
||||
case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;
|
||||
// SECONDS
|
||||
case 'U': $dates .= $d; break;
|
||||
case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;
|
||||
// AM/PM
|
||||
// Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
|
||||
case 'a':
|
||||
if ($hour>=12) $dates .= 'pm';
|
||||
else $dates .= 'am';
|
||||
break;
|
||||
case 'A':
|
||||
if ($hour>=12) $dates .= 'PM';
|
||||
else $dates .= 'AM';
|
||||
break;
|
||||
default:
|
||||
$dates .= $fmt[$i]; break;
|
||||
// ESCAPE
|
||||
case "\\":
|
||||
$i++;
|
||||
if ($i < $max) $dates .= $fmt[$i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $dates;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a timestamp given a GMT/UTC time.
|
||||
Note that $is_dst is not implemented and is ignored.
|
||||
*/
|
||||
function adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false)
|
||||
{
|
||||
return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true);
|
||||
}
|
||||
|
||||
/**
|
||||
Return a timestamp given a local time. Originally by jackbbs.
|
||||
Note that $is_dst is not implemented and is ignored.
|
||||
|
||||
Not a very fast algorithm - O(n) operation. Could be optimized to O(1).
|
||||
|
||||
NOTE: returns time() when the year is > 9999
|
||||
*/
|
||||
function adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false)
|
||||
{
|
||||
if (!defined('ADODB_TEST_DATES')) {
|
||||
|
||||
if ($mon === false) {
|
||||
return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec);
|
||||
}
|
||||
|
||||
// for windows, we don't check 1970 because with timezone differences,
|
||||
// 1 Jan 1970 could generate negative timestamp, which is illegal
|
||||
$usephpfns = (1971 < $year && $year < 2038
|
||||
|| !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038)
|
||||
);
|
||||
|
||||
|
||||
if ($usephpfns && ($year + $mon/12+$day/365.25+$hr/(24*365.25) >= 2038)) $usephpfns = false;
|
||||
|
||||
if ($usephpfns) {
|
||||
return $is_gmt ?
|
||||
@gmmktime($hr,$min,$sec,$mon,$day,$year):
|
||||
@mktime($hr,$min,$sec,$mon,$day,$year);
|
||||
}
|
||||
}
|
||||
|
||||
$gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff($year,$mon,$day);
|
||||
|
||||
/*
|
||||
# disabled because some people place large values in $sec.
|
||||
# however we need it for $mon because we use an array...
|
||||
$hr = (int)$hr;
|
||||
$min = (int)$min;
|
||||
$sec = (int)$sec;
|
||||
*/
|
||||
$mon = (int)$mon;
|
||||
$day = (int)$day;
|
||||
$year = (int)$year;
|
||||
|
||||
|
||||
$year = adodb_year_digit_check($year);
|
||||
|
||||
if ($mon > 12) {
|
||||
$y = floor(($mon-1)/ 12);
|
||||
$year += $y;
|
||||
$mon -= $y*12;
|
||||
} else if ($mon < 1) {
|
||||
$y = ceil((1-$mon) / 12);
|
||||
$year -= $y;
|
||||
$mon += $y*12;
|
||||
}
|
||||
|
||||
$_day_power = 86400;
|
||||
$_hour_power = 3600;
|
||||
$_min_power = 60;
|
||||
|
||||
$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
|
||||
$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
|
||||
|
||||
$_total_date = 0;
|
||||
if($year > 9999) {
|
||||
return time();
|
||||
} else if ($year >= 1970) {
|
||||
for ($a = 1970 ; $a <= $year; $a++) {
|
||||
$leaf = _adodb_is_leap_year($a);
|
||||
if ($leaf == true) {
|
||||
$loop_table = $_month_table_leaf;
|
||||
$_add_date = 366;
|
||||
} else {
|
||||
$loop_table = $_month_table_normal;
|
||||
$_add_date = 365;
|
||||
}
|
||||
if ($a < $year) {
|
||||
$_total_date += $_add_date;
|
||||
} else {
|
||||
for($b=1;$b<$mon;$b++) {
|
||||
$_total_date += $loop_table[$b];
|
||||
}
|
||||
}
|
||||
}
|
||||
$_total_date +=$day-1;
|
||||
$ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;
|
||||
|
||||
} else {
|
||||
for ($a = 1969 ; $a >= $year; $a--) {
|
||||
$leaf = _adodb_is_leap_year($a);
|
||||
if ($leaf == true) {
|
||||
$loop_table = $_month_table_leaf;
|
||||
$_add_date = 366;
|
||||
} else {
|
||||
$loop_table = $_month_table_normal;
|
||||
$_add_date = 365;
|
||||
}
|
||||
if ($a > $year) { $_total_date += $_add_date;
|
||||
} else {
|
||||
for($b=12;$b>$mon;$b--) {
|
||||
$_total_date += $loop_table[$b];
|
||||
}
|
||||
}
|
||||
}
|
||||
$_total_date += $loop_table[$mon] - $day;
|
||||
|
||||
$_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
|
||||
$_day_time = $_day_power - $_day_time;
|
||||
$ret = -( $_total_date * $_day_power + $_day_time - $gmt_different);
|
||||
if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction
|
||||
else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.
|
||||
}
|
||||
//print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function adodb_gmstrftime($fmt, $ts=false)
|
||||
{
|
||||
return adodb_strftime($fmt,$ts,true);
|
||||
}
|
||||
|
||||
// hack - convert to adodb_date
|
||||
function adodb_strftime($fmt, $ts=false,$is_gmt=false)
|
||||
{
|
||||
global $ADODB_DATE_LOCALE;
|
||||
|
||||
if (!defined('ADODB_TEST_DATES')) {
|
||||
if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
|
||||
if (!defined('ADODB_NO_NEGATIVE_TS') || $ts >= 0) // if windows, must be +ve integer
|
||||
return ($is_gmt)? @gmstrftime($fmt,$ts): @strftime($fmt,$ts);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($ADODB_DATE_LOCALE)) {
|
||||
/*
|
||||
$tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 1 am
|
||||
$sep = substr($tstr,2,1);
|
||||
$hasAM = strrpos($tstr,'M') !== false;
|
||||
*/
|
||||
# see http://phplens.com/lens/lensforum/msgs.php?id=14865 for reasoning, and changelog for version 0.24
|
||||
$dstr = gmstrftime('%x',31366800); // 30 Dec 1970, 1 am
|
||||
$sep = substr($dstr,2,1);
|
||||
$tstr = strtoupper(gmstrftime('%X',31366800)); // 30 Dec 1970, 1 am
|
||||
$hasAM = strrpos($tstr,'M') !== false;
|
||||
|
||||
$ADODB_DATE_LOCALE = array();
|
||||
$ADODB_DATE_LOCALE[] = strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y';
|
||||
$ADODB_DATE_LOCALE[] = ($hasAM) ? 'h:i:s a' : 'H:i:s';
|
||||
|
||||
}
|
||||
$inpct = false;
|
||||
$fmtdate = '';
|
||||
for ($i=0,$max = strlen($fmt); $i < $max; $i++) {
|
||||
$ch = $fmt[$i];
|
||||
if ($ch == '%') {
|
||||
if ($inpct) {
|
||||
$fmtdate .= '%';
|
||||
$inpct = false;
|
||||
} else
|
||||
$inpct = true;
|
||||
} else if ($inpct) {
|
||||
|
||||
$inpct = false;
|
||||
switch($ch) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case 'E':
|
||||
case 'O':
|
||||
/* ignore format modifiers */
|
||||
$inpct = true;
|
||||
break;
|
||||
|
||||
case 'a': $fmtdate .= 'D'; break;
|
||||
case 'A': $fmtdate .= 'l'; break;
|
||||
case 'h':
|
||||
case 'b': $fmtdate .= 'M'; break;
|
||||
case 'B': $fmtdate .= 'F'; break;
|
||||
case 'c': $fmtdate .= $ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break;
|
||||
case 'C': $fmtdate .= '\C?'; break; // century
|
||||
case 'd': $fmtdate .= 'd'; break;
|
||||
case 'D': $fmtdate .= 'm/d/y'; break;
|
||||
case 'e': $fmtdate .= 'j'; break;
|
||||
case 'g': $fmtdate .= '\g?'; break; //?
|
||||
case 'G': $fmtdate .= '\G?'; break; //?
|
||||
case 'H': $fmtdate .= 'H'; break;
|
||||
case 'I': $fmtdate .= 'h'; break;
|
||||
case 'j': $fmtdate .= '?z'; $parsej = true; break; // wrong as j=1-based, z=0-basd
|
||||
case 'm': $fmtdate .= 'm'; break;
|
||||
case 'M': $fmtdate .= 'i'; break;
|
||||
case 'n': $fmtdate .= "\n"; break;
|
||||
case 'p': $fmtdate .= 'a'; break;
|
||||
case 'r': $fmtdate .= 'h:i:s a'; break;
|
||||
case 'R': $fmtdate .= 'H:i:s'; break;
|
||||
case 'S': $fmtdate .= 's'; break;
|
||||
case 't': $fmtdate .= "\t"; break;
|
||||
case 'T': $fmtdate .= 'H:i:s'; break;
|
||||
case 'u': $fmtdate .= '?u'; $parseu = true; break; // wrong strftime=1-based, date=0-based
|
||||
case 'U': $fmtdate .= '?U'; $parseU = true; break;// wrong strftime=1-based, date=0-based
|
||||
case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break;
|
||||
case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break;
|
||||
case 'w': $fmtdate .= '?w'; $parseu = true; break; // wrong strftime=1-based, date=0-based
|
||||
case 'W': $fmtdate .= '?W'; $parseU = true; break;// wrong strftime=1-based, date=0-based
|
||||
case 'y': $fmtdate .= 'y'; break;
|
||||
case 'Y': $fmtdate .= 'Y'; break;
|
||||
case 'Z': $fmtdate .= 'T'; break;
|
||||
}
|
||||
} else if (('A' <= ($ch) && ($ch) <= 'Z' ) || ('a' <= ($ch) && ($ch) <= 'z' ))
|
||||
$fmtdate .= "\\".$ch;
|
||||
else
|
||||
$fmtdate .= $ch;
|
||||
}
|
||||
//echo "fmt=",$fmtdate,"<br>";
|
||||
if ($ts === false) $ts = time();
|
||||
$ret = adodb_date($fmtdate, $ts, $is_gmt);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
903
webroot/forum/inc/functions_upload.php
Normal file
903
webroot/forum/inc/functions_upload.php
Normal file
@@ -0,0 +1,903 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Remove an attachment from a specific post
|
||||
*
|
||||
* @param int $pid The post ID
|
||||
* @param string $posthash The posthash if available
|
||||
* @param int $aid The attachment ID
|
||||
*/
|
||||
function remove_attachment($pid, $posthash, $aid)
|
||||
{
|
||||
global $db, $mybb, $plugins;
|
||||
$aid = (int)$aid;
|
||||
$posthash = $db->escape_string($posthash);
|
||||
if(!empty($posthash))
|
||||
{
|
||||
$query = $db->simple_select("attachments", "aid, attachname, thumbnail, visible", "aid='{$aid}' AND posthash='{$posthash}'");
|
||||
$attachment = $db->fetch_array($query);
|
||||
}
|
||||
else
|
||||
{
|
||||
$query = $db->simple_select("attachments", "aid, attachname, thumbnail, visible", "aid='{$aid}' AND pid='{$pid}'");
|
||||
$attachment = $db->fetch_array($query);
|
||||
}
|
||||
|
||||
$plugins->run_hooks("remove_attachment_do_delete", $attachment);
|
||||
|
||||
if($attachment === false)
|
||||
{
|
||||
// no attachment found with the given details
|
||||
return;
|
||||
}
|
||||
|
||||
$db->delete_query("attachments", "aid='{$attachment['aid']}'");
|
||||
|
||||
if(defined('IN_ADMINCP'))
|
||||
{
|
||||
$uploadpath = '../'.$mybb->settings['uploadspath'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$uploadpath = $mybb->settings['uploadspath'];
|
||||
}
|
||||
|
||||
// Check if this attachment is referenced in any other posts. If it isn't, then we are safe to delete the actual file.
|
||||
$query = $db->simple_select("attachments", "COUNT(aid) as numreferences", "attachname='".$db->escape_string($attachment['attachname'])."'");
|
||||
if($db->fetch_field($query, "numreferences") == 0)
|
||||
{
|
||||
delete_uploaded_file($uploadpath."/".$attachment['attachname']);
|
||||
if($attachment['thumbnail'])
|
||||
{
|
||||
delete_uploaded_file($uploadpath."/".$attachment['thumbnail']);
|
||||
}
|
||||
|
||||
$date_directory = explode('/', $attachment['attachname']);
|
||||
if(@is_dir($uploadpath."/".$date_directory[0]))
|
||||
{
|
||||
delete_upload_directory($uploadpath."/".$date_directory[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if($attachment['visible'] == 1 && $pid)
|
||||
{
|
||||
$post = get_post($pid);
|
||||
update_thread_counters($post['tid'], array("attachmentcount" => "-1"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all of the attachments from a specific post
|
||||
*
|
||||
* @param int $pid The post ID
|
||||
* @param string $posthash The posthash if available
|
||||
*/
|
||||
function remove_attachments($pid, $posthash="")
|
||||
{
|
||||
global $db, $mybb, $plugins;
|
||||
|
||||
if($pid)
|
||||
{
|
||||
$post = get_post($pid);
|
||||
}
|
||||
$posthash = $db->escape_string($posthash);
|
||||
if($posthash != "" && !$pid)
|
||||
{
|
||||
$query = $db->simple_select("attachments", "*", "posthash='$posthash'");
|
||||
}
|
||||
else
|
||||
{
|
||||
$query = $db->simple_select("attachments", "*", "pid='$pid'");
|
||||
}
|
||||
|
||||
if(defined('IN_ADMINCP'))
|
||||
{
|
||||
$uploadpath = '../'.$mybb->settings['uploadspath'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$uploadpath = $mybb->settings['uploadspath'];
|
||||
}
|
||||
|
||||
$num_attachments = 0;
|
||||
while($attachment = $db->fetch_array($query))
|
||||
{
|
||||
if($attachment['visible'] == 1)
|
||||
{
|
||||
$num_attachments++;
|
||||
}
|
||||
|
||||
$plugins->run_hooks("remove_attachments_do_delete", $attachment);
|
||||
|
||||
$db->delete_query("attachments", "aid='".$attachment['aid']."'");
|
||||
|
||||
// Check if this attachment is referenced in any other posts. If it isn't, then we are safe to delete the actual file.
|
||||
$query2 = $db->simple_select("attachments", "COUNT(aid) as numreferences", "attachname='".$db->escape_string($attachment['attachname'])."'");
|
||||
if($db->fetch_field($query2, "numreferences") == 0)
|
||||
{
|
||||
delete_uploaded_file($uploadpath."/".$attachment['attachname']);
|
||||
if($attachment['thumbnail'])
|
||||
{
|
||||
delete_uploaded_file($uploadpath."/".$attachment['thumbnail']);
|
||||
}
|
||||
|
||||
$date_directory = explode('/', $attachment['attachname']);
|
||||
if(@is_dir($uploadpath."/".$date_directory[0]))
|
||||
{
|
||||
delete_upload_directory($uploadpath."/".$date_directory[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($post['tid'])
|
||||
{
|
||||
update_thread_counters($post['tid'], array("attachmentcount" => "-{$num_attachments}"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any matching avatars for a specific user ID
|
||||
*
|
||||
* @param int $uid The user ID
|
||||
* @param string $exclude A file name to be excluded from the removal
|
||||
*/
|
||||
function remove_avatars($uid, $exclude="")
|
||||
{
|
||||
global $mybb, $plugins;
|
||||
|
||||
if(defined('IN_ADMINCP'))
|
||||
{
|
||||
$avatarpath = '../'.$mybb->settings['avataruploadpath'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$avatarpath = $mybb->settings['avataruploadpath'];
|
||||
}
|
||||
|
||||
$dir = opendir($avatarpath);
|
||||
if($dir)
|
||||
{
|
||||
while($file = @readdir($dir))
|
||||
{
|
||||
$plugins->run_hooks("remove_avatars_do_delete", $file);
|
||||
|
||||
if(preg_match("#avatar_".$uid."\.#", $file) && is_file($avatarpath."/".$file) && $file != $exclude)
|
||||
{
|
||||
delete_uploaded_file($avatarpath."/".$file);
|
||||
}
|
||||
}
|
||||
|
||||
@closedir($dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a new avatar in to the file system
|
||||
*
|
||||
* @param array $avatar Incoming FILE array, if we have one - otherwise takes $_FILES['avatarupload']
|
||||
* @param int $uid User ID this avatar is being uploaded for, if not the current user
|
||||
* @return array Array of errors if any, otherwise filename of successful.
|
||||
*/
|
||||
function upload_avatar($avatar=array(), $uid=0)
|
||||
{
|
||||
global $db, $mybb, $lang, $plugins, $cache;
|
||||
|
||||
$ret = array();
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
$uid = $mybb->user['uid'];
|
||||
}
|
||||
|
||||
if(!$avatar['name'] || !$avatar['tmp_name'])
|
||||
{
|
||||
$avatar = $_FILES['avatarupload'];
|
||||
}
|
||||
|
||||
if(!is_uploaded_file($avatar['tmp_name']))
|
||||
{
|
||||
$ret['error'] = $lang->error_uploadfailed;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Check we have a valid extension
|
||||
$ext = get_extension(my_strtolower($avatar['name']));
|
||||
if(!preg_match("#^(gif|jpg|jpeg|jpe|bmp|png)$#i", $ext))
|
||||
{
|
||||
$ret['error'] = $lang->error_avatartype;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if(defined('IN_ADMINCP'))
|
||||
{
|
||||
$avatarpath = '../'.$mybb->settings['avataruploadpath'];
|
||||
$lang->load("messages", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$avatarpath = $mybb->settings['avataruploadpath'];
|
||||
}
|
||||
|
||||
$filename = "avatar_".$uid.".".$ext;
|
||||
$file = upload_file($avatar, $avatarpath, $filename);
|
||||
if($file['error'])
|
||||
{
|
||||
delete_uploaded_file($avatarpath."/".$filename);
|
||||
$ret['error'] = $lang->error_uploadfailed;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Lets just double check that it exists
|
||||
if(!file_exists($avatarpath."/".$filename))
|
||||
{
|
||||
$ret['error'] = $lang->error_uploadfailed;
|
||||
delete_uploaded_file($avatarpath."/".$filename);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Check if this is a valid image or not
|
||||
$img_dimensions = @getimagesize($avatarpath."/".$filename);
|
||||
if(!is_array($img_dimensions))
|
||||
{
|
||||
delete_uploaded_file($avatarpath."/".$filename);
|
||||
$ret['error'] = $lang->error_uploadfailed;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Check avatar dimensions
|
||||
if($mybb->settings['maxavatardims'] != '')
|
||||
{
|
||||
list($maxwidth, $maxheight) = @preg_split('/[|x]/', $mybb->settings['maxavatardims']);
|
||||
if(($maxwidth && $img_dimensions[0] > $maxwidth) || ($maxheight && $img_dimensions[1] > $maxheight))
|
||||
{
|
||||
// Automatic resizing enabled?
|
||||
if($mybb->settings['avatarresizing'] == "auto" || ($mybb->settings['avatarresizing'] == "user" && $mybb->input['auto_resize'] == 1))
|
||||
{
|
||||
require_once MYBB_ROOT."inc/functions_image.php";
|
||||
$thumbnail = generate_thumbnail($avatarpath."/".$filename, $avatarpath, $filename, $maxheight, $maxwidth);
|
||||
if(!$thumbnail['filename'])
|
||||
{
|
||||
$ret['error'] = $lang->sprintf($lang->error_avatartoobig, $maxwidth, $maxheight);
|
||||
$ret['error'] .= "<br /><br />".$lang->error_avatarresizefailed;
|
||||
delete_uploaded_file($avatarpath."/".$filename);
|
||||
return $ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy scaled image to CDN
|
||||
copy_file_to_cdn($avatarpath . '/' . $thumbnail['filename']);
|
||||
// Reset filesize
|
||||
$avatar['size'] = filesize($avatarpath."/".$filename);
|
||||
// Reset dimensions
|
||||
$img_dimensions = @getimagesize($avatarpath."/".$filename);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret['error'] = $lang->sprintf($lang->error_avatartoobig, $maxwidth, $maxheight);
|
||||
if($mybb->settings['avatarresizing'] == "user")
|
||||
{
|
||||
$ret['error'] .= "<br /><br />".$lang->error_avataruserresize;
|
||||
}
|
||||
delete_uploaded_file($avatarpath."/".$filename);
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check a list of known MIME types to establish what kind of avatar we're uploading
|
||||
$attachtypes = (array)$cache->read('attachtypes');
|
||||
|
||||
$allowed_mime_types = array();
|
||||
foreach($attachtypes as $attachtype)
|
||||
{
|
||||
if(defined('IN_ADMINCP') || is_member($attachtype['groups']) && $attachtype['avatarfile'])
|
||||
{
|
||||
$allowed_mime_types[$attachtype['mimetype']] = $attachtype['maxsize'];
|
||||
}
|
||||
}
|
||||
|
||||
$avatar['type'] = my_strtolower($avatar['type']);
|
||||
|
||||
switch($avatar['type'])
|
||||
{
|
||||
case "image/gif":
|
||||
$img_type = 1;
|
||||
break;
|
||||
case "image/jpeg":
|
||||
case "image/x-jpg":
|
||||
case "image/x-jpeg":
|
||||
case "image/pjpeg":
|
||||
case "image/jpg":
|
||||
$img_type = 2;
|
||||
break;
|
||||
case "image/png":
|
||||
case "image/x-png":
|
||||
$img_type = 3;
|
||||
break;
|
||||
case "image/bmp":
|
||||
case "image/x-bmp":
|
||||
case "image/x-windows-bmp":
|
||||
$img_type = 6;
|
||||
break;
|
||||
default:
|
||||
$img_type = 0;
|
||||
}
|
||||
|
||||
// Check if the uploaded file type matches the correct image type (returned by getimagesize)
|
||||
if(empty($allowed_mime_types[$avatar['type']]) || $img_dimensions[2] != $img_type || $img_type == 0)
|
||||
{
|
||||
$ret['error'] = $lang->error_uploadfailed;
|
||||
delete_uploaded_file($avatarpath."/".$filename);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Next check the file size
|
||||
if(($mybb->settings['avatarsize'] > 0 && $avatar['size'] > ($mybb->settings['avatarsize']*1024)) || $avatar['size'] > ($allowed_mime_types[$avatar['type']]*1024))
|
||||
{
|
||||
delete_uploaded_file($avatarpath."/".$filename);
|
||||
$ret['error'] = $lang->error_uploadsize;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Everything is okay so lets delete old avatars for this user
|
||||
remove_avatars($uid, $filename);
|
||||
|
||||
$ret = array(
|
||||
"avatar" => $mybb->settings['avataruploadpath']."/".$filename,
|
||||
"width" => (int)$img_dimensions[0],
|
||||
"height" => (int)$img_dimensions[1]
|
||||
);
|
||||
$ret = $plugins->run_hooks("upload_avatar_end", $ret);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload an attachment in to the file system
|
||||
*
|
||||
* @param array $attachment Attachment data (as fed by PHPs $_FILE)
|
||||
* @param boolean $update_attachment Whether or not we are updating a current attachment or inserting a new one
|
||||
* @return array Array of attachment data if successful, otherwise array of error data
|
||||
*/
|
||||
function upload_attachment($attachment, $update_attachment=false)
|
||||
{
|
||||
global $mybb, $db, $theme, $templates, $posthash, $pid, $tid, $forum, $mybb, $lang, $plugins, $cache;
|
||||
|
||||
$posthash = $db->escape_string($mybb->get_input('posthash'));
|
||||
$pid = (int)$pid;
|
||||
|
||||
if(isset($attachment['error']) && $attachment['error'] != 0)
|
||||
{
|
||||
$ret['error'] = $lang->error_uploadfailed.$lang->error_uploadfailed_detail;
|
||||
switch($attachment['error'])
|
||||
{
|
||||
case 1: // UPLOAD_ERR_INI_SIZE
|
||||
$ret['error'] .= $lang->error_uploadfailed_php1;
|
||||
break;
|
||||
case 2: // UPLOAD_ERR_FORM_SIZE
|
||||
$ret['error'] .= $lang->error_uploadfailed_php2;
|
||||
break;
|
||||
case 3: // UPLOAD_ERR_PARTIAL
|
||||
$ret['error'] .= $lang->error_uploadfailed_php3;
|
||||
break;
|
||||
case 4: // UPLOAD_ERR_NO_FILE
|
||||
$ret['error'] .= $lang->error_uploadfailed_php4;
|
||||
break;
|
||||
case 6: // UPLOAD_ERR_NO_TMP_DIR
|
||||
$ret['error'] .= $lang->error_uploadfailed_php6;
|
||||
break;
|
||||
case 7: // UPLOAD_ERR_CANT_WRITE
|
||||
$ret['error'] .= $lang->error_uploadfailed_php7;
|
||||
break;
|
||||
default:
|
||||
$ret['error'] .= $lang->sprintf($lang->error_uploadfailed_phpx, $attachment['error']);
|
||||
break;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if(!is_uploaded_file($attachment['tmp_name']) || empty($attachment['tmp_name']))
|
||||
{
|
||||
$ret['error'] = $lang->error_uploadfailed.$lang->error_uploadfailed_php4;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$attachtypes = (array)$cache->read('attachtypes');
|
||||
$attachment = $plugins->run_hooks("upload_attachment_start", $attachment);
|
||||
|
||||
$allowed_mime_types = array();
|
||||
foreach($attachtypes as $ext => $attachtype)
|
||||
{
|
||||
if(!is_member($attachtype['groups']) || ($attachtype['forums'] != -1 && strpos(','.$attachtype['forums'].',', ','.$forum['fid'].',') === false))
|
||||
{
|
||||
unset($attachtypes[$ext]);
|
||||
}
|
||||
}
|
||||
|
||||
$ext = get_extension($attachment['name']);
|
||||
// Check if we have a valid extension
|
||||
if(!isset($attachtypes[$ext]))
|
||||
{
|
||||
$ret['error'] = $lang->error_attachtype;
|
||||
return $ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
$attachtype = $attachtypes[$ext];
|
||||
}
|
||||
|
||||
// Check the size
|
||||
if($attachment['size'] > $attachtype['maxsize']*1024 && $attachtype['maxsize'] != "")
|
||||
{
|
||||
$ret['error'] = $lang->sprintf($lang->error_attachsize, htmlspecialchars_uni($attachment['name']), $attachtype['maxsize']);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Double check attachment space usage
|
||||
if($mybb->usergroup['attachquota'] > 0)
|
||||
{
|
||||
$query = $db->simple_select("attachments", "SUM(filesize) AS ausage", "uid='".$mybb->user['uid']."'");
|
||||
$usage = $db->fetch_array($query);
|
||||
$usage = $usage['ausage']+$attachment['size'];
|
||||
if($usage > ($mybb->usergroup['attachquota']*1024))
|
||||
{
|
||||
$friendlyquota = get_friendly_size($mybb->usergroup['attachquota']*1024);
|
||||
$ret['error'] = $lang->sprintf($lang->error_reachedattachquota, $friendlyquota);
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
// Gather forum permissions
|
||||
$forumpermissions = forum_permissions($forum['fid']);
|
||||
|
||||
// Check if an attachment with this name is already in the post
|
||||
if($pid != 0)
|
||||
{
|
||||
$uploaded_query = "pid='{$pid}'";
|
||||
}
|
||||
else
|
||||
{
|
||||
$uploaded_query = "posthash='{$posthash}'";
|
||||
}
|
||||
$query = $db->simple_select("attachments", "*", "filename='".$db->escape_string($attachment['name'])."' AND ".$uploaded_query);
|
||||
$prevattach = $db->fetch_array($query);
|
||||
if($prevattach['aid'] && $update_attachment == false)
|
||||
{
|
||||
if(!$mybb->usergroup['caneditattachments'] && !$forumpermissions['caneditattachments'])
|
||||
{
|
||||
$ret['error'] = $lang->error_alreadyuploaded_perm;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$ret['error'] = $lang->sprintf($lang->error_alreadyuploaded, htmlspecialchars_uni($attachment['name']));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Check to see how many attachments exist for this post already
|
||||
if($mybb->settings['maxattachments'] > 0 && $update_attachment == false)
|
||||
{
|
||||
$query = $db->simple_select("attachments", "COUNT(aid) AS numattachs", $uploaded_query);
|
||||
$attachcount = $db->fetch_field($query, "numattachs");
|
||||
if($attachcount >= $mybb->settings['maxattachments'])
|
||||
{
|
||||
$ret['error'] = $lang->sprintf($lang->error_maxattachpost, $mybb->settings['maxattachments']);
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
$month_dir = '';
|
||||
if($mybb->safemode == false)
|
||||
{
|
||||
// Check if the attachment directory (YYYYMM) exists, if not, create it
|
||||
$month_dir = gmdate("Ym");
|
||||
if(!@is_dir($mybb->settings['uploadspath']."/".$month_dir))
|
||||
{
|
||||
@mkdir($mybb->settings['uploadspath']."/".$month_dir);
|
||||
// Still doesn't exist - oh well, throw it in the main directory
|
||||
if(!@is_dir($mybb->settings['uploadspath']."/".$month_dir))
|
||||
{
|
||||
$month_dir = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$index = @fopen($mybb->settings['uploadspath']."/".$month_dir."/index.html", 'w');
|
||||
@fwrite($index, "<html>\n<head>\n<title></title>\n</head>\n<body>\n \n</body>\n</html>");
|
||||
@fclose($index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All seems to be good, lets move the attachment!
|
||||
$filename = "post_".$mybb->user['uid']."_".TIME_NOW."_".md5(random_str()).".attach";
|
||||
|
||||
$file = upload_file($attachment, $mybb->settings['uploadspath']."/".$month_dir, $filename);
|
||||
|
||||
// Failed to create the attachment in the monthly directory, just throw it in the main directory
|
||||
if(!empty($file['error']) && $month_dir)
|
||||
{
|
||||
$file = upload_file($attachment, $mybb->settings['uploadspath'].'/', $filename);
|
||||
}
|
||||
elseif($month_dir)
|
||||
{
|
||||
$filename = $month_dir."/".$filename;
|
||||
}
|
||||
|
||||
if(!empty($file['error']))
|
||||
{
|
||||
$ret['error'] = $lang->error_uploadfailed.$lang->error_uploadfailed_detail;
|
||||
switch($file['error'])
|
||||
{
|
||||
case 1:
|
||||
$ret['error'] .= $lang->error_uploadfailed_nothingtomove;
|
||||
break;
|
||||
case 2:
|
||||
$ret['error'] .= $lang->error_uploadfailed_movefailed;
|
||||
break;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Lets just double check that it exists
|
||||
if(!file_exists($mybb->settings['uploadspath']."/".$filename))
|
||||
{
|
||||
$ret['error'] = $lang->error_uploadfailed.$lang->error_uploadfailed_detail.$lang->error_uploadfailed_lost;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Generate the array for the insert_query
|
||||
$attacharray = array(
|
||||
"pid" => $pid,
|
||||
"posthash" => $posthash,
|
||||
"uid" => $mybb->user['uid'],
|
||||
"filename" => $db->escape_string($file['original_filename']),
|
||||
"filetype" => $db->escape_string($file['type']),
|
||||
"filesize" => (int)$file['size'],
|
||||
"attachname" => $filename,
|
||||
"downloads" => 0,
|
||||
"dateuploaded" => TIME_NOW
|
||||
);
|
||||
|
||||
// If we're uploading an image, check the MIME type compared to the image type and attempt to generate a thumbnail
|
||||
if($ext == "gif" || $ext == "png" || $ext == "jpg" || $ext == "jpeg" || $ext == "jpe")
|
||||
{
|
||||
// Check a list of known MIME types to establish what kind of image we're uploading
|
||||
switch(my_strtolower($file['type']))
|
||||
{
|
||||
case "image/gif":
|
||||
$img_type = 1;
|
||||
break;
|
||||
case "image/jpeg":
|
||||
case "image/x-jpg":
|
||||
case "image/x-jpeg":
|
||||
case "image/pjpeg":
|
||||
case "image/jpg":
|
||||
$img_type = 2;
|
||||
break;
|
||||
case "image/png":
|
||||
case "image/x-png":
|
||||
$img_type = 3;
|
||||
break;
|
||||
default:
|
||||
$img_type = 0;
|
||||
}
|
||||
|
||||
$supported_mimes = array();
|
||||
foreach($attachtypes as $attachtype)
|
||||
{
|
||||
if(!empty($attachtype['mimetype']))
|
||||
{
|
||||
$supported_mimes[] = $attachtype['mimetype'];
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the uploaded file type matches the correct image type (returned by getimagesize)
|
||||
$img_dimensions = @getimagesize($mybb->settings['uploadspath']."/".$filename);
|
||||
|
||||
$mime = "";
|
||||
$file_path = $mybb->settings['uploadspath']."/".$filename;
|
||||
if(function_exists("finfo_open"))
|
||||
{
|
||||
$file_info = finfo_open(FILEINFO_MIME);
|
||||
list($mime, ) = explode(';', finfo_file($file_info, MYBB_ROOT.$file_path), 1);
|
||||
finfo_close($file_info);
|
||||
}
|
||||
else if(function_exists("mime_content_type"))
|
||||
{
|
||||
$mime = mime_content_type(MYBB_ROOT.$file_path);
|
||||
}
|
||||
|
||||
if(!is_array($img_dimensions) || ($img_dimensions[2] != $img_type && !in_array($mime, $supported_mimes)))
|
||||
{
|
||||
delete_uploaded_file($mybb->settings['uploadspath']."/".$filename);
|
||||
$ret['error'] = $lang->error_uploadfailed;
|
||||
return $ret;
|
||||
}
|
||||
require_once MYBB_ROOT."inc/functions_image.php";
|
||||
$thumbname = str_replace(".attach", "_thumb.$ext", $filename);
|
||||
|
||||
$attacharray = $plugins->run_hooks("upload_attachment_thumb_start", $attacharray);
|
||||
|
||||
$thumbnail = generate_thumbnail($mybb->settings['uploadspath']."/".$filename, $mybb->settings['uploadspath'], $thumbname, $mybb->settings['attachthumbh'], $mybb->settings['attachthumbw']);
|
||||
|
||||
if($thumbnail['filename'])
|
||||
{
|
||||
$attacharray['thumbnail'] = $thumbnail['filename'];
|
||||
}
|
||||
elseif($thumbnail['code'] == 4)
|
||||
{
|
||||
$attacharray['thumbnail'] = "SMALL";
|
||||
}
|
||||
}
|
||||
if($forumpermissions['modattachments'] == 1 && !is_moderator($forum['fid'], "canapproveunapproveattachs"))
|
||||
{
|
||||
$attacharray['visible'] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$attacharray['visible'] = 1;
|
||||
}
|
||||
|
||||
$attacharray = $plugins->run_hooks("upload_attachment_do_insert", $attacharray);
|
||||
|
||||
if($prevattach['aid'] && $update_attachment == true)
|
||||
{
|
||||
unset($attacharray['downloads']); // Keep our download count if we're updating an attachment
|
||||
$db->update_query("attachments", $attacharray, "aid='".$db->escape_string($prevattach['aid'])."'");
|
||||
|
||||
// Remove old attachment file
|
||||
// Check if this attachment is referenced in any other posts. If it isn't, then we are safe to delete the actual file.
|
||||
$query = $db->simple_select("attachments", "COUNT(aid) as numreferences", "attachname='".$db->escape_string($prevattach['attachname'])."'");
|
||||
if($db->fetch_field($query, "numreferences") == 0)
|
||||
{
|
||||
delete_uploaded_file($mybb->settings['uploadspath']."/".$prevattach['attachname']);
|
||||
if($prevattach['thumbnail'])
|
||||
{
|
||||
delete_uploaded_file($mybb->settings['uploadspath']."/".$prevattach['thumbnail']);
|
||||
}
|
||||
|
||||
$date_directory = explode('/', $prevattach['attachname']);
|
||||
if(@is_dir($mybb->settings['uploadspath']."/".$date_directory[0]))
|
||||
{
|
||||
delete_upload_directory($mybb->settings['uploadspath']."/".$date_directory[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$aid = $prevattach['aid'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$aid = $db->insert_query("attachments", $attacharray);
|
||||
if($pid)
|
||||
{
|
||||
update_thread_counters($tid, array("attachmentcount" => "+1"));
|
||||
}
|
||||
}
|
||||
$ret['aid'] = $aid;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process adding attachment(s) when the "Add Attachment" button is pressed.
|
||||
*
|
||||
* @param int $pid The ID of the post.
|
||||
* @param array $forumpermission The permissions for the forum.
|
||||
* @param string $attachwhere Search string "pid='$pid'" or "posthash='".$db->escape_string($mybb->get_input('posthash'))."'"
|
||||
* @param string $action Where called from: "newthread", "newreply", or "editpost"
|
||||
*
|
||||
* @return array Array of errors if any, empty array otherwise
|
||||
*/
|
||||
function add_attachments($pid, $forumpermissions, $attachwhere, $action=false)
|
||||
{
|
||||
global $db, $mybb, $editdraftpid, $lang;
|
||||
|
||||
$ret = array();
|
||||
|
||||
if($forumpermissions['canpostattachments'])
|
||||
{
|
||||
$attachments = array();
|
||||
$fields = array ('name', 'type', 'tmp_name', 'error', 'size');
|
||||
$aid = array();
|
||||
|
||||
$total = isset($_FILES['attachments']['name']) ? count($_FILES['attachments']['name']) : 0;
|
||||
$filenames = "";
|
||||
$delim = "";
|
||||
for($i=0; $i<$total; ++$i)
|
||||
{
|
||||
foreach($fields as $field)
|
||||
{
|
||||
$attach1[$field] = $_FILES['attachments'][$field][$key];
|
||||
$attachments[$i][$field] = $_FILES['attachments'][$field][$i];
|
||||
}
|
||||
|
||||
$FILE = $attachments[$i];
|
||||
if(!empty($FILE['name']) && !empty($FILE['type']) && $FILE['size'] > 0)
|
||||
{
|
||||
$filenames .= $delim . "'" . $db->escape_string($FILE['name']) . "'";
|
||||
$delim = ",";
|
||||
}
|
||||
}
|
||||
|
||||
if ($filenames != '')
|
||||
{
|
||||
$query = $db->simple_select("attachments", "filename", "{$attachwhere} AND filename IN (".$filenames.")");
|
||||
|
||||
while ($row = $db->fetch_array($query))
|
||||
{
|
||||
$aid[$row['filename']] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($attachments as $FILE)
|
||||
{
|
||||
if(!empty($FILE['name']) && !empty($FILE['type']))
|
||||
{
|
||||
if($FILE['size'] > 0)
|
||||
{
|
||||
$filename = $db->escape_string($FILE['name']);
|
||||
$exists = $aid[$filename];
|
||||
|
||||
$update_attachment = false;
|
||||
if($action == "editpost")
|
||||
{
|
||||
if($exists && $mybb->get_input('updateattachment') && ($mybb->usergroup['caneditattachments'] || $forumpermissions['caneditattachments']))
|
||||
{
|
||||
$update_attachment = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($exists && $mybb->get_input('updateattachment'))
|
||||
{
|
||||
$update_attachment = true;
|
||||
}
|
||||
}
|
||||
|
||||
$attachedfile = upload_attachment($FILE, $update_attachment);
|
||||
|
||||
if(!empty($attachedfile['error']))
|
||||
{
|
||||
$ret['errors'][] = $attachedfile['error'];
|
||||
$mybb->input['action'] = $action;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret['errors'][] = $lang->sprintf($lang->error_uploadempty, htmlspecialchars_uni($FILE['name']));
|
||||
$mybb->input['action'] = $action;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an uploaded file both from the relative path and the CDN path if a CDN is in use.
|
||||
*
|
||||
* @param string $path The relative path to the uploaded file.
|
||||
*
|
||||
* @return bool Whether the file was deleted successfully.
|
||||
*/
|
||||
function delete_uploaded_file($path = '')
|
||||
{
|
||||
global $mybb, $plugins;
|
||||
|
||||
$deleted = false;
|
||||
|
||||
$deleted = @unlink($path);
|
||||
|
||||
$cdn_base_path = rtrim($mybb->settings['cdnpath'], '/');
|
||||
$path = ltrim($path, '/');
|
||||
$cdn_path = realpath($cdn_base_path . '/' . $path);
|
||||
|
||||
if($mybb->settings['usecdn'] && !empty($cdn_base_path))
|
||||
{
|
||||
$deleted = $deleted && @unlink($cdn_path);
|
||||
}
|
||||
|
||||
$hook_params = array(
|
||||
'path' => &$path,
|
||||
'deleted' => &$deleted,
|
||||
);
|
||||
|
||||
$plugins->run_hooks('delete_uploaded_file', $hook_params);
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an upload directory on both the local filesystem and the CDN filesystem.
|
||||
*
|
||||
* @param string $path The directory to delete.
|
||||
*
|
||||
* @return bool Whether the directory was deleted.
|
||||
*/
|
||||
function delete_upload_directory($path = '')
|
||||
{
|
||||
global $mybb, $plugins;
|
||||
|
||||
$deleted = false;
|
||||
|
||||
$deleted = @rmdir($path);
|
||||
|
||||
$cdn_base_path = rtrim($mybb->settings['cdnpath'], '/');
|
||||
$path = ltrim($path, '/');
|
||||
$cdn_path = rtrim(realpath($cdn_base_path . '/' . $path), '/');
|
||||
|
||||
if($mybb->settings['usecdn'] && !empty($cdn_base_path))
|
||||
{
|
||||
$deleted = $deleted && @rmdir($cdn_path);
|
||||
}
|
||||
|
||||
$hook_params = array(
|
||||
'path' => &$path,
|
||||
'deleted' => &$deleted,
|
||||
);
|
||||
|
||||
$plugins->run_hooks('delete_upload_directory', $hook_params);
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually move a file to the uploads directory
|
||||
*
|
||||
* @param array $file The PHP $_FILE array for the file
|
||||
* @param string $path The path to save the file in
|
||||
* @param string $filename The filename for the file (if blank, current is used)
|
||||
* @return array The uploaded file
|
||||
*/
|
||||
function upload_file($file, $path, $filename="")
|
||||
{
|
||||
global $plugins, $mybb;
|
||||
|
||||
$upload = array();
|
||||
|
||||
if(empty($file['name']) || $file['name'] == "none" || $file['size'] < 1)
|
||||
{
|
||||
$upload['error'] = 1;
|
||||
return $upload;
|
||||
}
|
||||
|
||||
if(!$filename)
|
||||
{
|
||||
$filename = $file['name'];
|
||||
}
|
||||
|
||||
$upload['original_filename'] = preg_replace("#/$#", "", $file['name']); // Make the filename safe
|
||||
$filename = preg_replace("#/$#", "", $filename); // Make the filename safe
|
||||
$moved = @move_uploaded_file($file['tmp_name'], $path."/".$filename);
|
||||
|
||||
$cdn_path = '';
|
||||
|
||||
$moved_cdn = copy_file_to_cdn($path."/".$filename, $cdn_path);
|
||||
|
||||
if(!$moved)
|
||||
{
|
||||
$upload['error'] = 2;
|
||||
return $upload;
|
||||
}
|
||||
@my_chmod($path."/".$filename, '0644');
|
||||
$upload['filename'] = $filename;
|
||||
$upload['path'] = $path;
|
||||
$upload['type'] = $file['type'];
|
||||
$upload['size'] = $file['size'];
|
||||
$upload = $plugins->run_hooks("upload_file_end", $upload);
|
||||
|
||||
if($moved_cdn)
|
||||
{
|
||||
$upload['cdn_path'] = $cdn_path;
|
||||
}
|
||||
|
||||
return $upload;
|
||||
}
|
||||
820
webroot/forum/inc/functions_user.php
Normal file
820
webroot/forum/inc/functions_user.php
Normal file
@@ -0,0 +1,820 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks if a user with uid $uid exists in the database.
|
||||
*
|
||||
* @param int $uid The uid to check for.
|
||||
* @return boolean True when exists, false when not.
|
||||
*/
|
||||
function user_exists($uid)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$query = $db->simple_select("users", "COUNT(*) as user", "uid='".(int)$uid."'", array('limit' => 1));
|
||||
if($db->fetch_field($query, 'user') == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if $username already exists in the database.
|
||||
*
|
||||
* @param string $username The username for check for.
|
||||
* @return boolean True when exists, false when not.
|
||||
*/
|
||||
function username_exists($username)
|
||||
{
|
||||
$options = array(
|
||||
'username_method' => 2
|
||||
);
|
||||
|
||||
return (bool)get_user_by_username($username, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a password with a supplied username.
|
||||
*
|
||||
* @param string $username The username of the user.
|
||||
* @param string $password The plain-text password.
|
||||
* @return boolean|array False when no match, array with user info when match.
|
||||
*/
|
||||
function validate_password_from_username($username, $password)
|
||||
{
|
||||
global $mybb;
|
||||
|
||||
$options = array(
|
||||
'fields' => '*',
|
||||
'username_method' => $mybb->settings['username_method'],
|
||||
);
|
||||
|
||||
$user = get_user_by_username($username, $options);
|
||||
|
||||
if(!$user['uid'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return validate_password_from_uid($user['uid'], $password, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a password with a supplied uid.
|
||||
*
|
||||
* @param int $uid The user id.
|
||||
* @param string $password The plain-text password.
|
||||
* @param array $user An optional user data array.
|
||||
* @return boolean|array False when not valid, user data array when valid.
|
||||
*/
|
||||
function validate_password_from_uid($uid, $password, $user = array())
|
||||
{
|
||||
global $db, $mybb;
|
||||
if(isset($mybb->user['uid']) && $mybb->user['uid'] == $uid)
|
||||
{
|
||||
$user = $mybb->user;
|
||||
}
|
||||
if(!$user['password'])
|
||||
{
|
||||
$user = get_user($uid);
|
||||
}
|
||||
if(!$user['salt'])
|
||||
{
|
||||
// Generate a salt for this user and assume the password stored in db is a plain md5 password
|
||||
$password_fields = create_password($user['password'], false, $user);
|
||||
$db->update_query("users", $password_fields, "uid='".$user['uid']."'");
|
||||
}
|
||||
|
||||
if(!$user['loginkey'])
|
||||
{
|
||||
$user['loginkey'] = generate_loginkey();
|
||||
$sql_array = array(
|
||||
"loginkey" => $user['loginkey']
|
||||
);
|
||||
$db->update_query("users", $sql_array, "uid = ".$user['uid']);
|
||||
}
|
||||
if(verify_user_password($user, $password))
|
||||
{
|
||||
return $user;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a user's password.
|
||||
*
|
||||
* @param int $uid The user's id.
|
||||
* @param string $password The md5()'ed password.
|
||||
* @param string $salt (Optional) The salt of the user.
|
||||
* @return array The new password.
|
||||
* @deprecated deprecated since version 1.8.6 Please use other alternatives.
|
||||
*/
|
||||
function update_password($uid, $password, $salt="")
|
||||
{
|
||||
global $db, $plugins;
|
||||
|
||||
$newpassword = array();
|
||||
|
||||
// If no salt was specified, check in database first, if still doesn't exist, create one
|
||||
if(!$salt)
|
||||
{
|
||||
$query = $db->simple_select("users", "salt", "uid='$uid'");
|
||||
$user = $db->fetch_array($query);
|
||||
if($user['salt'])
|
||||
{
|
||||
$salt = $user['salt'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$salt = generate_salt();
|
||||
}
|
||||
$newpassword['salt'] = $salt;
|
||||
}
|
||||
|
||||
// Create new password based on salt
|
||||
$saltedpw = salt_password($password, $salt);
|
||||
|
||||
// Generate new login key
|
||||
$loginkey = generate_loginkey();
|
||||
|
||||
// Update password and login key in database
|
||||
$newpassword['password'] = $saltedpw;
|
||||
$newpassword['loginkey'] = $loginkey;
|
||||
$db->update_query("users", $newpassword, "uid='$uid'");
|
||||
|
||||
$plugins->run_hooks("password_changed");
|
||||
|
||||
return $newpassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Salts a password based on a supplied salt.
|
||||
*
|
||||
* @param string $password The md5()'ed password.
|
||||
* @param string $salt The salt.
|
||||
* @return string The password hash.
|
||||
* @deprecated deprecated since version 1.8.9 Please use other alternatives.
|
||||
*/
|
||||
function salt_password($password, $salt)
|
||||
{
|
||||
return md5(md5($salt).$password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Salts a password based on a supplied salt.
|
||||
*
|
||||
* @param string $password The input password.
|
||||
* @param string $salt (Optional) The salt used by the MyBB algorithm.
|
||||
* @param string $user (Optional) An array containing password-related data.
|
||||
* @return array Password-related fields.
|
||||
*/
|
||||
function create_password($password, $salt = false, $user = false)
|
||||
{
|
||||
global $plugins;
|
||||
|
||||
$fields = null;
|
||||
|
||||
$parameters = compact('password', 'salt', 'user', 'fields');
|
||||
|
||||
if(!defined('IN_INSTALL') && !defined('IN_UPGRADE'))
|
||||
{
|
||||
$plugins->run_hooks('create_password', $parameters);
|
||||
}
|
||||
|
||||
if(!is_null($parameters['fields']))
|
||||
{
|
||||
$fields = $parameters['fields'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$salt)
|
||||
{
|
||||
$salt = generate_salt();
|
||||
}
|
||||
|
||||
$hash = md5(md5($salt).md5($password));
|
||||
|
||||
$fields = array(
|
||||
'salt' => $salt,
|
||||
'password' => $hash,
|
||||
);
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares user's password data against provided input.
|
||||
*
|
||||
* @param array $user An array containing password-related data.
|
||||
* @param string $password The plain-text input password.
|
||||
* @return bool Result of the comparison.
|
||||
*/
|
||||
function verify_user_password($user, $password)
|
||||
{
|
||||
global $plugins;
|
||||
|
||||
$result = null;
|
||||
|
||||
$parameters = compact('user', 'password', 'result');
|
||||
|
||||
if(!defined('IN_INSTALL') && !defined('IN_UPGRADE'))
|
||||
{
|
||||
$plugins->run_hooks('verify_user_password', $parameters);
|
||||
}
|
||||
|
||||
if(!is_null($parameters['result']))
|
||||
{
|
||||
return $parameters['result'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$password_fields = create_password($password, $user['salt'], $user);
|
||||
|
||||
return my_hash_equals($user['password'], $password_fields['password']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random salt
|
||||
*
|
||||
* @return string The salt.
|
||||
*/
|
||||
function generate_salt()
|
||||
{
|
||||
return random_str(8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a 50 character random login key.
|
||||
*
|
||||
* @return string The login key.
|
||||
*/
|
||||
function generate_loginkey()
|
||||
{
|
||||
return random_str(50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a user's salt in the database (does not update a password).
|
||||
*
|
||||
* @param int $uid The uid of the user to update.
|
||||
* @return string The new salt.
|
||||
*/
|
||||
function update_salt($uid)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$salt = generate_salt();
|
||||
$sql_array = array(
|
||||
"salt" => $salt
|
||||
);
|
||||
$db->update_query("users", $sql_array, "uid='{$uid}'");
|
||||
|
||||
return $salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new login key for a user.
|
||||
*
|
||||
* @param int $uid The uid of the user to update.
|
||||
* @return string The new login key.
|
||||
*/
|
||||
function update_loginkey($uid)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$loginkey = generate_loginkey();
|
||||
$sql_array = array(
|
||||
"loginkey" => $loginkey
|
||||
);
|
||||
$db->update_query("users", $sql_array, "uid='{$uid}'");
|
||||
|
||||
return $loginkey;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a thread to a user's thread subscription list.
|
||||
* If no uid is supplied, the currently logged in user's id will be used.
|
||||
*
|
||||
* @param int $tid The tid of the thread to add to the list.
|
||||
* @param int $notification (Optional) The type of notification to receive for replies (0=none, 1=email, 2=pm)
|
||||
* @param int $uid (Optional) The uid of the user who's list to update.
|
||||
* @return boolean True when success, false when otherwise.
|
||||
*/
|
||||
function add_subscribed_thread($tid, $notification=1, $uid=0)
|
||||
{
|
||||
global $mybb, $db;
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
$uid = $mybb->user['uid'];
|
||||
}
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = $db->simple_select("threadsubscriptions", "*", "tid='".(int)$tid."' AND uid='".(int)$uid."'");
|
||||
$subscription = $db->fetch_array($query);
|
||||
if(!$subscription['tid'])
|
||||
{
|
||||
$insert_array = array(
|
||||
'uid' => (int)$uid,
|
||||
'tid' => (int)$tid,
|
||||
'notification' => (int)$notification,
|
||||
'dateline' => TIME_NOW
|
||||
);
|
||||
$db->insert_query("threadsubscriptions", $insert_array);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Subscription exists - simply update notification
|
||||
$update_array = array(
|
||||
"notification" => (int)$notification
|
||||
);
|
||||
$db->update_query("threadsubscriptions", $update_array, "uid='{$uid}' AND tid='{$tid}'");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a thread from a user's thread subscription list.
|
||||
* If no uid is supplied, the currently logged in user's id will be used.
|
||||
*
|
||||
* @param int $tid The tid of the thread to remove from the list.
|
||||
* @param int $uid (Optional) The uid of the user who's list to update.
|
||||
* @return boolean True when success, false when otherwise.
|
||||
*/
|
||||
function remove_subscribed_thread($tid, $uid=0)
|
||||
{
|
||||
global $mybb, $db;
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
$uid = $mybb->user['uid'];
|
||||
}
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$db->delete_query("threadsubscriptions", "tid='".$tid."' AND uid='{$uid}'");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a forum to a user's forum subscription list.
|
||||
* If no uid is supplied, the currently logged in user's id will be used.
|
||||
*
|
||||
* @param int $fid The fid of the forum to add to the list.
|
||||
* @param int $uid (Optional) The uid of the user who's list to update.
|
||||
* @return boolean True when success, false when otherwise.
|
||||
*/
|
||||
function add_subscribed_forum($fid, $uid=0)
|
||||
{
|
||||
global $mybb, $db;
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
$uid = $mybb->user['uid'];
|
||||
}
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$fid = (int)$fid;
|
||||
$uid = (int)$uid;
|
||||
|
||||
$query = $db->simple_select("forumsubscriptions", "*", "fid='".$fid."' AND uid='{$uid}'", array('limit' => 1));
|
||||
$fsubscription = $db->fetch_array($query);
|
||||
if(!$fsubscription['fid'])
|
||||
{
|
||||
$insert_array = array(
|
||||
'fid' => $fid,
|
||||
'uid' => $uid
|
||||
);
|
||||
$db->insert_query("forumsubscriptions", $insert_array);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a forum from a user's forum subscription list.
|
||||
* If no uid is supplied, the currently logged in user's id will be used.
|
||||
*
|
||||
* @param int $fid The fid of the forum to remove from the list.
|
||||
* @param int $uid (Optional) The uid of the user who's list to update.
|
||||
* @return boolean True when success, false when otherwise.
|
||||
*/
|
||||
function remove_subscribed_forum($fid, $uid=0)
|
||||
{
|
||||
global $mybb, $db;
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
$uid = $mybb->user['uid'];
|
||||
}
|
||||
|
||||
if(!$uid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$db->delete_query("forumsubscriptions", "fid='".$fid."' AND uid='{$uid}'");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the usercp navigation menu.
|
||||
*
|
||||
*/
|
||||
function usercp_menu()
|
||||
{
|
||||
global $mybb, $templates, $theme, $plugins, $lang, $usercpnav, $usercpmenu;
|
||||
|
||||
$lang->load("usercpnav");
|
||||
|
||||
// Add the default items as plugins with separated priorities of 10
|
||||
if($mybb->settings['enablepms'] != 0 && $mybb->usergroup['canusepms'] == 1)
|
||||
{
|
||||
$plugins->add_hook("usercp_menu", "usercp_menu_messenger", 10);
|
||||
}
|
||||
|
||||
if($mybb->usergroup['canusercp'] == 1)
|
||||
{
|
||||
$plugins->add_hook("usercp_menu", "usercp_menu_profile", 20);
|
||||
$plugins->add_hook("usercp_menu", "usercp_menu_misc", 30);
|
||||
}
|
||||
|
||||
// Run the plugin hooks
|
||||
$plugins->run_hooks("usercp_menu");
|
||||
global $usercpmenu;
|
||||
|
||||
if($mybb->usergroup['canusercp'] == 1)
|
||||
{
|
||||
eval("\$ucp_nav_home = \"".$templates->get("usercp_nav_home")."\";");
|
||||
}
|
||||
|
||||
eval("\$usercpnav = \"".$templates->get("usercp_nav")."\";");
|
||||
|
||||
$plugins->run_hooks("usercp_menu_built");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the usercp messenger menu.
|
||||
*
|
||||
*/
|
||||
function usercp_menu_messenger()
|
||||
{
|
||||
global $db, $mybb, $templates, $theme, $usercpmenu, $lang, $collapse, $collapsed, $collapsedimg;
|
||||
|
||||
$expaltext = (in_array("usercppms", $collapse)) ? "[+]" : "[-]";
|
||||
$usercp_nav_messenger = $templates->get("usercp_nav_messenger");
|
||||
// Hide tracking link if no permission
|
||||
$tracking = '';
|
||||
if($mybb->usergroup['cantrackpms'])
|
||||
{
|
||||
$tracking = $templates->get("usercp_nav_messenger_tracking");
|
||||
}
|
||||
eval("\$ucp_nav_tracking = \"". $tracking ."\";");
|
||||
|
||||
// Hide compose link if no permission
|
||||
$ucp_nav_compose = '';
|
||||
if($mybb->usergroup['cansendpms'] == 1)
|
||||
{
|
||||
eval("\$ucp_nav_compose = \"".$templates->get("usercp_nav_messenger_compose")."\";");
|
||||
}
|
||||
|
||||
$folderlinks = $folder_id = $folder_name = '';
|
||||
$foldersexploded = explode("$%%$", $mybb->user['pmfolders']);
|
||||
foreach($foldersexploded as $key => $folders)
|
||||
{
|
||||
$folderinfo = explode("**", $folders, 2);
|
||||
$folderinfo[1] = get_pm_folder_name($folderinfo[0], $folderinfo[1]);
|
||||
if($folderinfo[0] == 4)
|
||||
{
|
||||
$class = "usercp_nav_trash_pmfolder";
|
||||
}
|
||||
else if($folderlinks)
|
||||
{
|
||||
$class = "usercp_nav_sub_pmfolder";
|
||||
}
|
||||
else
|
||||
{
|
||||
$class = "usercp_nav_pmfolder";
|
||||
}
|
||||
|
||||
$folder_id = $folderinfo[0];
|
||||
$folder_name = $folderinfo[1];
|
||||
|
||||
eval("\$folderlinks .= \"".$templates->get("usercp_nav_messenger_folder")."\";");
|
||||
}
|
||||
|
||||
if(!isset($collapsedimg['usercppms']))
|
||||
{
|
||||
$collapsedimg['usercppms'] = '';
|
||||
}
|
||||
|
||||
if(!isset($collapsed['usercppms_e']))
|
||||
{
|
||||
$collapsed['usercppms_e'] = '';
|
||||
}
|
||||
|
||||
eval("\$usercpmenu .= \"".$usercp_nav_messenger."\";");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the usercp profile menu.
|
||||
*
|
||||
*/
|
||||
function usercp_menu_profile()
|
||||
{
|
||||
global $db, $mybb, $templates, $theme, $usercpmenu, $lang, $collapse, $collapsed, $collapsedimg;
|
||||
|
||||
$changenameop = '';
|
||||
if($mybb->usergroup['canchangename'] != 0)
|
||||
{
|
||||
eval("\$changenameop = \"".$templates->get("usercp_nav_changename")."\";");
|
||||
}
|
||||
|
||||
$changesigop = '';
|
||||
if($mybb->usergroup['canusesig'] == 1 && ($mybb->usergroup['canusesigxposts'] == 0 || $mybb->usergroup['canusesigxposts'] > 0 && $mybb->user['postnum'] > $mybb->usergroup['canusesigxposts']))
|
||||
{
|
||||
if($mybb->user['suspendsignature'] == 0 || $mybb->user['suspendsignature'] == 1 && $mybb->user['suspendsigtime'] > 0 && $mybb->user['suspendsigtime'] < TIME_NOW)
|
||||
{
|
||||
eval("\$changesigop = \"".$templates->get("usercp_nav_editsignature")."\";");
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($collapsedimg['usercpprofile']))
|
||||
{
|
||||
$collapsedimg['usercpprofile'] = '';
|
||||
}
|
||||
|
||||
if(!isset($collapsed['usercpprofile_e']))
|
||||
{
|
||||
$collapsed['usercpprofile_e'] = '';
|
||||
}
|
||||
|
||||
$expaltext = (in_array("usercpprofile", $collapse)) ? "[+]" : "[-]";
|
||||
eval("\$usercpmenu .= \"".$templates->get("usercp_nav_profile")."\";");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the usercp misc menu.
|
||||
*
|
||||
*/
|
||||
function usercp_menu_misc()
|
||||
{
|
||||
global $db, $mybb, $templates, $theme, $usercpmenu, $lang, $collapse, $collapsed, $collapsedimg;
|
||||
|
||||
$draftstart = $draftend = '';
|
||||
$draftcount = $lang->ucp_nav_drafts;
|
||||
|
||||
$query = $db->simple_select("posts", "COUNT(pid) AS draftcount", "visible = '-2' AND uid = '{$mybb->user['uid']}'");
|
||||
$count = $db->fetch_field($query, 'draftcount');
|
||||
|
||||
if($count > 0)
|
||||
{
|
||||
$draftcount = $lang->sprintf($lang->ucp_nav_drafts_active, my_number_format($count));
|
||||
}
|
||||
|
||||
if($mybb->settings['enableattachments'] != 0)
|
||||
{
|
||||
eval("\$attachmentop = \"".$templates->get("usercp_nav_attachments")."\";");
|
||||
}
|
||||
|
||||
if(!isset($collapsedimg['usercpmisc']))
|
||||
{
|
||||
$collapsedimg['usercpmisc'] = '';
|
||||
}
|
||||
|
||||
if(!isset($collapsed['usercpmisc_e']))
|
||||
{
|
||||
$collapsed['usercpmisc_e'] = '';
|
||||
}
|
||||
|
||||
$profile_link = get_profile_link($mybb->user['uid']);
|
||||
$expaltext = (in_array("usercpmisc", $collapse)) ? "[+]" : "[-]";
|
||||
eval("\$usercpmenu .= \"".$templates->get("usercp_nav_misc")."\";");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the usertitle for a specific uid.
|
||||
*
|
||||
* @param int $uid The uid of the user to get the usertitle of.
|
||||
* @return string The usertitle of the user.
|
||||
*/
|
||||
function get_usertitle($uid=0)
|
||||
{
|
||||
global $db, $mybb;
|
||||
|
||||
if($mybb->user['uid'] == $uid)
|
||||
{
|
||||
$user = $mybb->user;
|
||||
}
|
||||
else
|
||||
{
|
||||
$query = $db->simple_select("users", "usertitle,postnum", "uid='$uid'", array('limit' => 1));
|
||||
$user = $db->fetch_array($query);
|
||||
}
|
||||
|
||||
if($user['usertitle'])
|
||||
{
|
||||
return $user['usertitle'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$usertitles = $mybb->cache->read('usertitles');
|
||||
foreach($usertitles as $title)
|
||||
{
|
||||
if($title['posts'] <= $user['postnum'])
|
||||
{
|
||||
$usertitle = $title;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $usertitle['title'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a users private message count in the users table with the number of pms they have.
|
||||
*
|
||||
* @param int $uid The user id to update the count for. If none, assumes currently logged in user.
|
||||
* @param int $count_to_update Bitwise value for what to update. 1 = total, 2 = new, 4 = unread. Combinations accepted.
|
||||
* @return array The updated counters
|
||||
*/
|
||||
function update_pm_count($uid=0, $count_to_update=7)
|
||||
{
|
||||
global $db, $mybb;
|
||||
|
||||
// If no user id, assume that we mean the current logged in user.
|
||||
if((int)$uid == 0)
|
||||
{
|
||||
$uid = $mybb->user['uid'];
|
||||
}
|
||||
|
||||
$uid = (int)$uid;
|
||||
$pmcount = array();
|
||||
if($uid == 0)
|
||||
{
|
||||
return $pmcount;
|
||||
}
|
||||
|
||||
// Update total number of messages.
|
||||
if($count_to_update & 1)
|
||||
{
|
||||
$query = $db->simple_select("privatemessages", "COUNT(pmid) AS pms_total", "uid='".$uid."'");
|
||||
$total = $db->fetch_array($query);
|
||||
$pmcount['totalpms'] = $total['pms_total'];
|
||||
}
|
||||
|
||||
// Update number of unread messages.
|
||||
if($count_to_update & 2 && $db->field_exists("unreadpms", "users") == true)
|
||||
{
|
||||
$query = $db->simple_select("privatemessages", "COUNT(pmid) AS pms_unread", "uid='".$uid."' AND status='0' AND folder='1'");
|
||||
$unread = $db->fetch_array($query);
|
||||
$pmcount['unreadpms'] = $unread['pms_unread'];
|
||||
}
|
||||
|
||||
if(!empty($pmcount))
|
||||
{
|
||||
$db->update_query("users", $pmcount, "uid='".$uid."'");
|
||||
}
|
||||
return $pmcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the language specific name for a PM folder.
|
||||
*
|
||||
* @param int $fid The ID of the folder.
|
||||
* @param string $name The folder name - can be blank, will use language default.
|
||||
* @return string The name of the folder.
|
||||
*/
|
||||
function get_pm_folder_name($fid, $name="")
|
||||
{
|
||||
global $lang;
|
||||
|
||||
if($name != '')
|
||||
{
|
||||
return $name;
|
||||
}
|
||||
|
||||
switch($fid)
|
||||
{
|
||||
case 0:
|
||||
return $lang->folder_inbox;
|
||||
break;
|
||||
case 1:
|
||||
return $lang->folder_unread;
|
||||
break;
|
||||
case 2:
|
||||
return $lang->folder_sent_items;
|
||||
break;
|
||||
case 3:
|
||||
return $lang->folder_drafts;
|
||||
break;
|
||||
case 4:
|
||||
return $lang->folder_trash;
|
||||
break;
|
||||
default:
|
||||
return $lang->folder_untitled;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a security question for registration.
|
||||
*
|
||||
* @param int $old_qid Optional ID of the old question.
|
||||
* @return string The question session id.
|
||||
*/
|
||||
function generate_question($old_qid=0)
|
||||
{
|
||||
global $db;
|
||||
|
||||
if($db->type == 'pgsql' || $db->type == 'sqlite')
|
||||
{
|
||||
$order_by = 'RANDOM()';
|
||||
}
|
||||
else
|
||||
{
|
||||
$order_by = 'RAND()';
|
||||
}
|
||||
|
||||
if($old_qid)
|
||||
{
|
||||
$excl_old = ' AND qid != '.(int)$old_qid;
|
||||
}
|
||||
|
||||
$query = $db->simple_select('questions', 'qid, shown', "active=1{$excl_old}", array('limit' => 1, 'order_by' => $order_by));
|
||||
$question = $db->fetch_array($query);
|
||||
|
||||
if(!$db->num_rows($query))
|
||||
{
|
||||
// No active questions exist
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sessionid = random_str(32);
|
||||
|
||||
$sql_array = array(
|
||||
"sid" => $sessionid,
|
||||
"qid" => $question['qid'],
|
||||
"dateline" => TIME_NOW
|
||||
);
|
||||
$db->insert_query("questionsessions", $sql_array);
|
||||
|
||||
$update_question = array(
|
||||
"shown" => $question['shown'] + 1
|
||||
);
|
||||
$db->update_query("questions", $update_question, "qid = '{$question['qid']}'");
|
||||
|
||||
return $sessionid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we can show the Purge Spammer Feature
|
||||
*
|
||||
* @param int $post_count The users post count
|
||||
* @param int $usergroup The usergroup of our user
|
||||
* @param int $uid The uid of our user
|
||||
* @return boolean Whether or not to show the feature
|
||||
*/
|
||||
function purgespammer_show($post_count, $usergroup, $uid)
|
||||
{
|
||||
global $mybb, $cache;
|
||||
|
||||
// only show this if the current user has permission to use it and the user has less than the post limit for using this tool
|
||||
$bangroup = $mybb->settings['purgespammerbangroup'];
|
||||
$usergroups = $cache->read('usergroups');
|
||||
|
||||
return ($mybb->user['uid'] != $uid && is_member($mybb->settings['purgespammergroups']) && !is_super_admin($uid)
|
||||
&& !$usergroups[$usergroup]['cancp'] && !$usergroups[$usergroup]['canmodcp'] && !$usergroups[$usergroup]['issupermod']
|
||||
&& (str_replace($mybb->settings['thousandssep'], '', $post_count) <= $mybb->settings['purgespammerpostlimit'] || $mybb->settings['purgespammerpostlimit'] == 0)
|
||||
&& !is_member($bangroup, $uid) && !$usergroups[$usergroup]['isbannedgroup']);
|
||||
}
|
||||
125
webroot/forum/inc/functions_warnings.php
Normal file
125
webroot/forum/inc/functions_warnings.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param resource|PDOStatement|mysqli_result $query The query to be run. Needs to select the "action" column of the "warninglevels" table
|
||||
* @param array $max_expiration_times Return variable. The maximum expiration time
|
||||
* @param array $check_levels Return variable. Whether those "levels" were checked
|
||||
*/
|
||||
function find_warnlevels_to_check($query, &$max_expiration_times, &$check_levels)
|
||||
{
|
||||
global $db;
|
||||
|
||||
// we have some warning levels we need to revoke
|
||||
$max_expiration_times = array(
|
||||
1 => -1, // Ban
|
||||
2 => -1, // Revoke posting
|
||||
3 => -1 // Moderate posting
|
||||
);
|
||||
$check_levels = array(
|
||||
1 => false, // Ban
|
||||
2 => false, // Revoke posting
|
||||
3 => false // Moderate posting
|
||||
);
|
||||
while($warn_level = $db->fetch_array($query))
|
||||
{
|
||||
// revoke actions taken at this warning level
|
||||
$action = my_unserialize($warn_level['action']);
|
||||
if($action['type'] < 1 || $action['type'] > 3) // prevent any freak-ish cases
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$check_levels[$action['type']] = true;
|
||||
|
||||
$max_exp_time = &$max_expiration_times[$action['type']];
|
||||
if($action['length'] && $max_exp_time != 0)
|
||||
{
|
||||
$expiration = $action['length'];
|
||||
if($expiration > $max_exp_time)
|
||||
{
|
||||
$max_exp_time = $expiration;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$max_exp_time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a friendly expiration time of a suspension/warning
|
||||
*
|
||||
* @param int $time The time period of the suspension/warning
|
||||
* @return array An array of the time/period remaining
|
||||
*/
|
||||
function fetch_friendly_expiration($time)
|
||||
{
|
||||
if($time == 0 || $time == -1)
|
||||
{
|
||||
return array("period" => "never");
|
||||
}
|
||||
else if($time % 2592000 == 0)
|
||||
{
|
||||
return array("time" => $time/2592000, "period" => "months");
|
||||
}
|
||||
else if($time % 604800 == 0)
|
||||
{
|
||||
return array("time" => $time/604800, "period" => "weeks");
|
||||
}
|
||||
else if($time % 86400 == 0)
|
||||
{
|
||||
return array("time" => $time/86400, "period" => "days");
|
||||
}
|
||||
else
|
||||
{
|
||||
return array("time" => ceil($time/3600), "period" => "hours");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Figures out the length of a suspension/warning
|
||||
*
|
||||
* @param int $time The amount of time to calculate the length of suspension/warning
|
||||
* @param string $period The period of time to calculate the length of suspension/warning
|
||||
* @return int Length of the suspension/warning (in seconds)
|
||||
*/
|
||||
function fetch_time_length($time, $period)
|
||||
{
|
||||
$time = (int)$time;
|
||||
|
||||
if($period == "hours")
|
||||
{
|
||||
$time = $time*3600;
|
||||
}
|
||||
else if($period == "days")
|
||||
{
|
||||
$time = $time*86400;
|
||||
}
|
||||
else if($period == "weeks")
|
||||
{
|
||||
$time = $time*604800;
|
||||
}
|
||||
else if($period == "months")
|
||||
{
|
||||
$time = $time*2592000;
|
||||
}
|
||||
else if($period == "never" && $time == 0)
|
||||
{
|
||||
// User is permanentely banned
|
||||
$time = "-1";
|
||||
}
|
||||
else
|
||||
{
|
||||
$time = 0;
|
||||
}
|
||||
return $time;
|
||||
}
|
||||
8
webroot/forum/inc/index.html
Normal file
8
webroot/forum/inc/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
308
webroot/forum/inc/init.php
Normal file
308
webroot/forum/inc/init.php
Normal file
@@ -0,0 +1,308 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
* Website: http://www.mybb.com
|
||||
* License: http://www.mybb.com/about/license
|
||||
*
|
||||
*/
|
||||
|
||||
// Disallow direct access to this file for security reasons
|
||||
if(!defined("IN_MYBB"))
|
||||
{
|
||||
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
|
||||
}
|
||||
|
||||
// Fallback
|
||||
if(!defined('THIS_SCRIPT'))
|
||||
{
|
||||
define('THIS_SCRIPT', 'unknown');
|
||||
}
|
||||
|
||||
/* Defines the root directory for MyBB.
|
||||
|
||||
Uncomment the below line and set the path manually
|
||||
if you experience problems.
|
||||
|
||||
Always add a trailing slash to the end of the path.
|
||||
|
||||
* Path to your copy of MyBB
|
||||
*/
|
||||
//define('MYBB_ROOT', "./");
|
||||
|
||||
// Attempt autodetection
|
||||
if(!defined('MYBB_ROOT'))
|
||||
{
|
||||
define('MYBB_ROOT', dirname(dirname(__FILE__))."/");
|
||||
}
|
||||
|
||||
define("TIME_NOW", time());
|
||||
|
||||
if(function_exists('date_default_timezone_set') && !ini_get('date.timezone'))
|
||||
{
|
||||
date_default_timezone_set('GMT');
|
||||
}
|
||||
|
||||
require_once MYBB_ROOT."inc/class_error.php";
|
||||
$error_handler = new errorHandler();
|
||||
|
||||
if(!function_exists('json_encode') || !function_exists('json_decode'))
|
||||
{
|
||||
require_once MYBB_ROOT.'inc/3rdparty/json/json.php';
|
||||
}
|
||||
|
||||
require_once MYBB_ROOT."inc/functions.php";
|
||||
|
||||
require_once MYBB_ROOT."inc/class_timers.php";
|
||||
$maintimer = new timer();
|
||||
|
||||
require_once MYBB_ROOT."inc/class_core.php";
|
||||
$mybb = new MyBB;
|
||||
|
||||
$not_installed = false;
|
||||
if(!file_exists(MYBB_ROOT."inc/config.php"))
|
||||
{
|
||||
$not_installed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Include the required core files
|
||||
require_once MYBB_ROOT."inc/config.php";
|
||||
$mybb->config = &$config;
|
||||
|
||||
if(!isset($config['database']))
|
||||
{
|
||||
$not_installed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($not_installed !== false)
|
||||
{
|
||||
if(file_exists(MYBB_ROOT."install/index.php"))
|
||||
{
|
||||
if(defined("IN_ARCHIVE") || defined("IN_ADMINCP"))
|
||||
{
|
||||
header("Location: ../install/index.php");
|
||||
exit;
|
||||
}
|
||||
header("Location: ./install/index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$mybb->trigger_generic_error("board_not_installed");
|
||||
}
|
||||
|
||||
if(!is_array($config['database']))
|
||||
{
|
||||
$mybb->trigger_generic_error("board_not_upgraded");
|
||||
}
|
||||
|
||||
if(empty($config['admin_dir']))
|
||||
{
|
||||
$config['admin_dir'] = "admin";
|
||||
}
|
||||
|
||||
// Trigger an error if the installation directory exists
|
||||
if(is_dir(MYBB_ROOT."install") && !file_exists(MYBB_ROOT."install/lock"))
|
||||
{
|
||||
$mybb->trigger_generic_error("install_directory");
|
||||
}
|
||||
|
||||
// Load DB interface
|
||||
require_once MYBB_ROOT."inc/db_base.php";
|
||||
|
||||
require_once MYBB_ROOT."inc/db_".$config['database']['type'].".php";
|
||||
|
||||
switch($config['database']['type'])
|
||||
{
|
||||
case "sqlite":
|
||||
$db = new DB_SQLite;
|
||||
break;
|
||||
case "pgsql":
|
||||
$db = new DB_PgSQL;
|
||||
break;
|
||||
case "mysqli":
|
||||
$db = new DB_MySQLi;
|
||||
break;
|
||||
default:
|
||||
$db = new DB_MySQL;
|
||||
}
|
||||
|
||||
// Check if our DB engine is loaded
|
||||
if(!extension_loaded($db->engine))
|
||||
{
|
||||
// Throw our super awesome db loading error
|
||||
$mybb->trigger_generic_error("sql_load_error");
|
||||
}
|
||||
|
||||
require_once MYBB_ROOT."inc/class_templates.php";
|
||||
$templates = new templates;
|
||||
|
||||
require_once MYBB_ROOT."inc/class_datacache.php";
|
||||
$cache = new datacache;
|
||||
|
||||
require_once MYBB_ROOT."inc/class_plugins.php";
|
||||
$plugins = new pluginSystem;
|
||||
|
||||
// Include our base data handler class
|
||||
require_once MYBB_ROOT."inc/datahandler.php";
|
||||
|
||||
// Connect to Database
|
||||
define("TABLE_PREFIX", $config['database']['table_prefix']);
|
||||
$db->connect($config['database']);
|
||||
$db->set_table_prefix(TABLE_PREFIX);
|
||||
$db->type = $config['database']['type'];
|
||||
|
||||
// Language initialisation
|
||||
require_once MYBB_ROOT."inc/class_language.php";
|
||||
$lang = new MyLanguage;
|
||||
$lang->set_path(MYBB_ROOT."inc/languages");
|
||||
|
||||
// Load cache
|
||||
$cache->cache();
|
||||
|
||||
// Load Settings
|
||||
if(file_exists(MYBB_ROOT."inc/settings.php"))
|
||||
{
|
||||
require_once MYBB_ROOT."inc/settings.php";
|
||||
}
|
||||
|
||||
if(!file_exists(MYBB_ROOT."inc/settings.php") || empty($settings))
|
||||
{
|
||||
if(function_exists('rebuild_settings'))
|
||||
{
|
||||
rebuild_settings();
|
||||
}
|
||||
else
|
||||
{
|
||||
$options = array(
|
||||
"order_by" => "title",
|
||||
"order_dir" => "ASC"
|
||||
);
|
||||
|
||||
$query = $db->simple_select("settings", "value, name", "", $options);
|
||||
|
||||
$settings = array();
|
||||
while($setting = $db->fetch_array($query))
|
||||
{
|
||||
$setting['value'] = str_replace("\"", "\\\"", $setting['value']);
|
||||
$settings[$setting['name']] = $setting['value'];
|
||||
}
|
||||
$db->free_result($query);
|
||||
}
|
||||
}
|
||||
|
||||
$settings['wolcutoff'] = $settings['wolcutoffmins']*60;
|
||||
$settings['bbname_orig'] = $settings['bbname'];
|
||||
$settings['bbname'] = strip_tags($settings['bbname']);
|
||||
$settings['orig_bblanguage'] = $settings['bblanguage'];
|
||||
|
||||
// Fix for people who for some specify a trailing slash on the board URL
|
||||
if(substr($settings['bburl'], -1) == "/")
|
||||
{
|
||||
$settings['bburl'] = my_substr($settings['bburl'], 0, -1);
|
||||
}
|
||||
|
||||
// Setup our internal settings and load our encryption key
|
||||
$settings['internal'] = $cache->read("internal_settings");
|
||||
if(!$settings['internal']['encryption_key'])
|
||||
{
|
||||
$cache->update("internal_settings", array('encryption_key' => random_str(32)));
|
||||
$settings['internal'] = $cache->read("internal_settings");
|
||||
}
|
||||
|
||||
$mybb->settings = &$settings;
|
||||
$mybb->parse_cookies();
|
||||
$mybb->cache = &$cache;
|
||||
$mybb->asset_url = $mybb->get_asset_url();
|
||||
|
||||
if($mybb->use_shutdown == true)
|
||||
{
|
||||
register_shutdown_function('run_shutdown');
|
||||
}
|
||||
|
||||
// Did we just upgrade to a new version and haven't run the upgrade scripts yet?
|
||||
$version = $cache->read("version");
|
||||
if(!defined("IN_INSTALL") && !defined("IN_UPGRADE") && $version['version_code'] < $mybb->version_code)
|
||||
{
|
||||
$version_history = $cache->read("version_history");
|
||||
if(empty($version_history) || file_exists(MYBB_ROOT."install/resources/upgrade".(int)(end($version_history)+1).".php"))
|
||||
{
|
||||
$mybb->trigger_generic_error("board_not_upgraded");
|
||||
}
|
||||
}
|
||||
|
||||
// Load plugins
|
||||
if(!defined("NO_PLUGINS") && !($mybb->settings['no_plugins'] == 1))
|
||||
{
|
||||
$plugins->load();
|
||||
}
|
||||
|
||||
// Set up any shutdown functions we need to run globally
|
||||
add_shutdown('send_mail_queue');
|
||||
|
||||
/* URL Definitions */
|
||||
if($mybb->settings['seourls'] == "yes" || ($mybb->settings['seourls'] == "auto" && isset($_SERVER['SEO_SUPPORT']) && $_SERVER['SEO_SUPPORT'] == 1))
|
||||
{
|
||||
$mybb->seo_support = true;
|
||||
|
||||
define('FORUM_URL', "forum-{fid}.html");
|
||||
define('FORUM_URL_PAGED', "forum-{fid}-page-{page}.html");
|
||||
define('THREAD_URL', "thread-{tid}.html");
|
||||
define('THREAD_URL_PAGED', "thread-{tid}-page-{page}.html");
|
||||
define('THREAD_URL_ACTION', 'thread-{tid}-{action}.html');
|
||||
define('THREAD_URL_POST', 'thread-{tid}-post-{pid}.html');
|
||||
define('POST_URL', "post-{pid}.html");
|
||||
define('PROFILE_URL', "user-{uid}.html");
|
||||
define('ANNOUNCEMENT_URL', "announcement-{aid}.html");
|
||||
define('CALENDAR_URL', "calendar-{calendar}.html");
|
||||
define('CALENDAR_URL_MONTH', 'calendar-{calendar}-year-{year}-month-{month}.html');
|
||||
define('CALENDAR_URL_DAY', 'calendar-{calendar}-year-{year}-month-{month}-day-{day}.html');
|
||||
define('CALENDAR_URL_WEEK', 'calendar-{calendar}-week-{week}.html');
|
||||
define('EVENT_URL', "event-{eid}.html");
|
||||
}
|
||||
else
|
||||
{
|
||||
define('FORUM_URL', "forumdisplay.php?fid={fid}");
|
||||
define('FORUM_URL_PAGED', "forumdisplay.php?fid={fid}&page={page}");
|
||||
define('THREAD_URL', "showthread.php?tid={tid}");
|
||||
define('THREAD_URL_PAGED', "showthread.php?tid={tid}&page={page}");
|
||||
define('THREAD_URL_ACTION', 'showthread.php?tid={tid}&action={action}');
|
||||
define('THREAD_URL_POST', 'showthread.php?tid={tid}&pid={pid}');
|
||||
define('POST_URL', "showthread.php?pid={pid}");
|
||||
define('PROFILE_URL', "member.php?action=profile&uid={uid}");
|
||||
define('ANNOUNCEMENT_URL', "announcements.php?aid={aid}");
|
||||
define('CALENDAR_URL', "calendar.php?calendar={calendar}");
|
||||
define('CALENDAR_URL_MONTH', "calendar.php?calendar={calendar}&year={year}&month={month}");
|
||||
define('CALENDAR_URL_DAY', 'calendar.php?action=dayview&calendar={calendar}&year={year}&month={month}&day={day}');
|
||||
define('CALENDAR_URL_WEEK', 'calendar.php?action=weekview&calendar={calendar}&week={week}');
|
||||
define('EVENT_URL', "calendar.php?action=event&eid={eid}");
|
||||
}
|
||||
define('INDEX_URL', "index.php");
|
||||
|
||||
// An array of valid date formats (Used for user selections etc)
|
||||
$date_formats = array(
|
||||
1 => "m-d-Y",
|
||||
2 => "m-d-y",
|
||||
3 => "m.d.Y",
|
||||
4 => "m.d.y",
|
||||
5 => "d-m-Y",
|
||||
6 => "d-m-y",
|
||||
7 => "d.m.Y",
|
||||
8 => "d.m.y",
|
||||
9 => "F jS, Y",
|
||||
10 => "l, F jS, Y",
|
||||
11 => "jS F, Y",
|
||||
12 => "l, jS F, Y",
|
||||
// ISO 8601
|
||||
13 => "Y-m-d"
|
||||
);
|
||||
|
||||
// An array of valid time formats (Used for user selections etc)
|
||||
$time_formats = array(
|
||||
1 => "h:i a",
|
||||
2 => "h:i A",
|
||||
3 => "H:i"
|
||||
);
|
||||
|
||||
30
webroot/forum/inc/languages/english.php
Normal file
30
webroot/forum/inc/languages/english.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* MyBB 1.8 English Language Pack
|
||||
* Copyright 2014 MyBB Group, All Rights Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
// The friendly name of the language
|
||||
$langinfo['name'] = "English (American)";
|
||||
|
||||
// The author of the language
|
||||
$langinfo['author'] = "MyBB Group";
|
||||
|
||||
// The language authors website
|
||||
$langinfo['website'] = "https://mybb.com/";
|
||||
|
||||
// Compatible version of MyBB
|
||||
$langinfo['version'] = "1821";
|
||||
|
||||
// Sets if the translation includes the Admin CP (1 = yes, 0 = no)
|
||||
$langinfo['admin'] = 1;
|
||||
|
||||
// Sets if the language is RTL (Right to Left) (1 = yes, 0 = no)
|
||||
$langinfo['rtl'] = 0;
|
||||
|
||||
// Sets the lang in the <html> on all pages
|
||||
$langinfo['htmllang'] = "en";
|
||||
|
||||
// Sets the character set, blank uses the default.
|
||||
$langinfo['charset'] = "UTF-8";
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user