inital commit

This commit is contained in:
2026-06-19 20:08:01 +06:00
commit 8a5abeeae4
13128 changed files with 3192007 additions and 0 deletions

View 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
View 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;
}
}

View 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]);
}
}
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View 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
{
}

View 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);
}
}
}
}

View 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);
}
}

View 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;
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View 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);
}
}

View 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, '! ');
}
}

View 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);
}
}

View 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);
}
}

View 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)
);
}
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View 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;
}
}

View 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;
}
}

View 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);
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

8
webroot/forum/inc/3rdparty/index.html vendored Normal file
View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

822
webroot/forum/inc/3rdparty/json/json.php vendored Normal file
View 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);
}

View 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;
}

View 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;
}
}

View 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;
}
}
}

View 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;
}
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View 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='');
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View 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 cant. After installing one of my fonts,
you may be able to select it in the above applications but the person at the other end wont
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 youre creating a web page using Flash, its easy. Consult your Flash manual. If
youre 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 youre 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 dont 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. Theres 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 cant be altered. Does that mean I cant
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 dont alter the font files in font creation software such as
FontLab or Fontographer youre 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 youre not sure. Its 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 wont 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 dont 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>

View 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;
}
}

View 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("&#077;&#089;&#066;&#066;");
}
}
/**
* 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'
);

View 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;
}
}

File diff suppressed because it is too large Load Diff

View 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'] = "&nbsp;";
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;
}
}

View 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", "&#x26;$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;
}
}
}

View 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;
}
}

View 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;
}
}

View 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]};
}
}

View 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;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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];
}
}

View 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);
}
}

View 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;
}

View 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;
}
}
}
}

View 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;
}
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View 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;
}
}

View 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;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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;
}
}

View 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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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 = " &gt; ";
$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; ?>, &copy; 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();
}
}
}

File diff suppressed because it is too large Load Diff

View 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", "&amp;", $forum['name']); // Fix & but allow unicode
$forum['description'] = preg_replace("#&(?!\#[0-9]+;)#si", "&amp;", $forum['description']); // Fix & but allow unicode
$forum['name'] = preg_replace("#&([^\#])(?![a-z1-4]{1,10};)#i", "&#038;$1", $forum['name']);
$forum['description'] = preg_replace("#&([^\#])(?![a-z1-4]{1,10};)#i", "&#038;$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
);
}

View 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;
}

View 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]");
}
}

View 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;
}

View 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('&amp;', '&', get_post_link($post['pid'], $thread['tid'])."#pid".$post['pid']);
break;
case 'profile':
$send_report_subject = $user['username'];
$send_report_url = str_replace('&amp;', '&', 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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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(=(?:&quot;|\"|')?.*?(?:&quot;|\"|')?)?\]#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";
}

View 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']}'");
}

File diff suppressed because it is too large Load Diff

View 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 = "&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."&amp;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;
}

View 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;
}

View 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;
}

View 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&nbsp;\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;
}

View 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']);
}

View 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;
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

308
webroot/forum/inc/init.php Normal file
View 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"
);

View 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