function wfArrayMap($function, $input)
{
    $ret = array_map($function, $input);
    foreach ($ret as $key => $value) {
        $taint = istainted($input[$key]);
        if ($taint) {
            taint($ret[$key], $taint);
        }
    }
    return $ret;
}
示例#2
0
 /**
  * Run an SQL query and return the result. Normally throws a DBQueryError
  * on failure. If errors are ignored, returns false instead.
  *
  * In new code, the query wrappers select(), insert(), update(), delete(),
  * etc. should be used where possible, since they give much better DBMS
  * independence and automatically quote or validate user input in a variety
  * of contexts. This function is generally only useful for queries which are
  * explicitly DBMS-dependent and are unsupported by the query wrappers, such
  * as CREATE TABLE.
  *
  * However, the query wrappers themselves should call this function.
  *
  * @param string $sql : SQL query
  * @param string $fname : Name of the calling function, for profiling/SHOW PROCESSLIST
  *     comment (you can use __METHOD__ or add some extra info)
  * @param bool $tempIgnore : Whether to avoid throwing an exception on errors...
  *     maybe best to catch the exception instead?
  *
  * @return bool|ResultWrapper true for a successful write query, ResultWrapper object
  *     for a successful read query, or false on failure if $tempIgnore set
  *
  * @throws DBQueryError
  * @throws MWException
  */
 public function query($sql, $fname = '', $tempIgnore = false)
 {
     $isMaster = !is_null($this->getLBInfo('master'));
     if (!Profiler::instance()->isStub()) {
         # generalizeSQL will probably cut down the query to reasonable
         # logging size most of the time. The substr is really just a sanity check.
         if ($isMaster) {
             $queryProf = 'query-m: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query-master';
         } else {
             $queryProf = 'query: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query';
         }
         wfProfileIn($totalProf);
         wfProfileIn($queryProf);
     }
     $this->mLastQuery = $sql;
     $is_writeable = $this->isWriteQuery($sql);
     if (!$this->mDoneWrites && $is_writeable) {
         # Set a flag indicating that writes have been done
         wfDebug(__METHOD__ . ": Writes done: {$sql}\n");
         $this->mDoneWrites = true;
     }
     # <Wikia>
     global $wgDBReadOnly;
     if ($is_writeable && $wgDBReadOnly) {
         if (!Profiler::instance()->isStub()) {
             wfProfileOut($queryProf);
             wfProfileOut($totalProf);
         }
         WikiaLogger::instance()->error('DB readonly mode', ['exception' => new Exception($sql), 'server' => $this->mServer]);
         wfDebug(sprintf("%s: DB read-only mode prevented the following query: %s\n", __METHOD__, $sql));
         return false;
     }
     # </Wikia>
     # Add a comment for easy SHOW PROCESSLIST interpretation
     global $wgUser;
     if (is_object($wgUser) && $wgUser->isItemLoaded('name')) {
         $userName = $wgUser->getName();
         if (mb_strlen($userName) > 15) {
             $userName = mb_substr($userName, 0, 15) . '...';
         }
         $userName = str_replace('/', '', $userName);
     } else {
         $userName = '';
     }
     # Wikia change - begin
     # @author macbre
     if ($fname === '') {
         wfDebug("Query: \$fname autogenerated, please pass __METHOD__ to the query() call!\n");
         $fname = wfGetCallerClassMethod(['WikiaSQL', 'FluentSql\\SQL', 'WikiaDataAccess', __CLASS__]);
     }
     # Wikia change - end
     $commentedSql = preg_replace('/\\s/', " /* {$fname} {$userName} */ ", $sql, 1);
     # Wikia change - begin
     # @author macbre
     # Add profiling data to queries like BEGIN or COMMIT (preg_replace above will not handle them)
     if (strpos($sql, ' ') === false) {
         $commentedSql = "{$sql} /* {$fname} {$userName} */";
     }
     # Wikia change - end
     # If DBO_TRX is set, start a transaction
     if ($this->mFlags & DBO_TRX && !$this->trxLevel() && $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK') {
         # avoid establishing transactions for SHOW and SET statements too -
         # that would delay transaction initializations to once connection
         # is really used by application
         $sqlstart = substr($sql, 0, 10);
         // very much worth it, benchmark certified(tm)
         if (strpos($sqlstart, "SHOW ") !== 0 && strpos($sqlstart, "SET ") !== 0) {
             $this->begin(__METHOD__ . " ({$fname})");
         }
     }
     if ($this->debug()) {
         static $cnt = 0;
         $cnt++;
         $sqlx = substr($commentedSql, 0, 500);
         $sqlx = strtr($sqlx, "\t\n", '  ');
         $master = $isMaster ? 'master' : 'slave';
         wfDebug("Query {$this->mDBname} ({$cnt}) ({$master}): {$sqlx}\n");
     }
     if (istainted($sql) & TC_MYSQL) {
         throw new MWException('Tainted query found');
     }
     $ret = $this->executeAndProfileQuery($commentedSql, $fname, $isMaster);
     # Try reconnecting if the connection was lost
     if (false === $ret && $this->wasErrorReissuable()) {
         # Transaction is gone, like it or not
         $this->mTrxLevel = 0;
         wfDebug("Connection lost, reconnecting...\n");
         if ($this->ping()) {
             wfDebug("Reconnected\n");
             $sqlx = substr($commentedSql, 0, 500);
             $sqlx = strtr($sqlx, "\t\n", '  ');
             global $wgRequestTime;
             $elapsed = round(microtime(true) - $wgRequestTime, 3);
             if ($elapsed < 300) {
                 # Not a database error to lose a transaction after a minute or two
                 wfLogDBError("Connection lost and reconnected after {$elapsed}s, query: {$sqlx}\n");
             }
             $ret = $this->executeAndProfileQuery($commentedSql, $fname, $isMaster);
         } else {
             wfDebug("Failed\n");
         }
     }
     if (false === $ret) {
         $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore);
     }
     if (!Profiler::instance()->isStub()) {
         wfProfileOut($queryProf);
         wfProfileOut($totalProf);
     }
     return $this->resultObject($ret);
 }
示例#3
0
 /**
  * Usually aborts on failure.  If errors are explicitly ignored, returns success.
  *
  * @param  $sql        String: SQL query
  * @param  $fname      String: Name of the calling function, for profiling/SHOW PROCESSLIST
  *     comment (you can use __METHOD__ or add some extra info)
  * @param  $tempIgnore Boolean:   Whether to avoid throwing an exception on errors...
  *     maybe best to catch the exception instead?
  * @return boolean or ResultWrapper. true for a successful write query, ResultWrapper object for a successful read query,
  *     or false on failure if $tempIgnore set
  * @throws DBQueryError Thrown when the database returns an error of any kind
  */
 public function query($sql, $fname = '', $tempIgnore = false)
 {
     global $wgProfiler;
     $isMaster = !is_null($this->getLBInfo('master'));
     if (isset($wgProfiler)) {
         # generalizeSQL will probably cut down the query to reasonable
         # logging size most of the time. The substr is really just a sanity check.
         # Who's been wasting my precious column space? -- TS
         # $profName = 'query: ' . $fname . ' ' . substr( DatabaseBase::generalizeSQL( $sql ), 0, 255 );
         if ($isMaster) {
             $queryProf = 'query-m: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query-master';
         } else {
             $queryProf = 'query: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query';
         }
         wfProfileIn($totalProf);
         wfProfileIn($queryProf);
     }
     $this->mLastQuery = $sql;
     if (!$this->mDoneWrites && $this->isWriteQuery($sql)) {
         // Set a flag indicating that writes have been done
         wfDebug(__METHOD__ . ": Writes done: {$sql}\n");
         $this->mDoneWrites = true;
     }
     # Add a comment for easy SHOW PROCESSLIST interpretation
     # if ( $fname ) {
     global $wgUser;
     if (is_object($wgUser) && $wgUser->mDataLoaded) {
         $userName = $wgUser->getName();
         if (mb_strlen($userName) > 15) {
             $userName = mb_substr($userName, 0, 15) . '...';
         }
         $userName = str_replace('/', '', $userName);
     } else {
         $userName = '';
     }
     $commentedSql = preg_replace('/\\s/', " /* {$fname} {$userName} */ ", $sql, 1);
     # } else {
     #	$commentedSql = $sql;
     # }
     # If DBO_TRX is set, start a transaction
     if ($this->mFlags & DBO_TRX && !$this->trxLevel() && $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK') {
         // avoid establishing transactions for SHOW and SET statements too -
         // that would delay transaction initializations to once connection
         // is really used by application
         $sqlstart = substr($sql, 0, 10);
         // very much worth it, benchmark certified(tm)
         if (strpos($sqlstart, "SHOW ") !== 0 and strpos($sqlstart, "SET ") !== 0) {
             $this->begin();
         }
     }
     if ($this->debug()) {
         static $cnt = 0;
         $cnt++;
         $sqlx = substr($commentedSql, 0, 500);
         $sqlx = strtr($sqlx, "\t\n", '  ');
         if ($isMaster) {
             wfDebug("Query {$cnt} (master): {$sqlx}\n");
         } else {
             wfDebug("Query {$cnt} (slave): {$sqlx}\n");
         }
     }
     if (istainted($sql) & TC_MYSQL) {
         throw new MWException('Tainted query found');
     }
     # Do the query and handle errors
     $ret = $this->doQuery($commentedSql);
     # Try reconnecting if the connection was lost
     if (false === $ret && $this->wasErrorReissuable()) {
         # Transaction is gone, like it or not
         $this->mTrxLevel = 0;
         wfDebug("Connection lost, reconnecting...\n");
         if ($this->ping()) {
             wfDebug("Reconnected\n");
             $sqlx = substr($commentedSql, 0, 500);
             $sqlx = strtr($sqlx, "\t\n", '  ');
             global $wgRequestTime;
             $elapsed = round(microtime(true) - $wgRequestTime, 3);
             if ($elapsed < 300) {
                 # Not a database error to lose a transaction after a minute or two
                 wfLogDBError("Connection lost and reconnected after {$elapsed}s, query: {$sqlx}\n");
             }
             $ret = $this->doQuery($commentedSql);
         } else {
             wfDebug("Failed\n");
         }
     }
     if (false === $ret) {
         $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore);
     }
     if (isset($wgProfiler)) {
         wfProfileOut($queryProf);
         wfProfileOut($totalProf);
     }
     return $this->resultObject($ret);
 }
 /**
  * Run an SQL query and return the result. Normally throws a DBQueryError
  * on failure. If errors are ignored, returns false instead.
  *
  * In new code, the query wrappers select(), insert(), update(), delete(),
  * etc. should be used where possible, since they give much better DBMS
  * independence and automatically quote or validate user input in a variety
  * of contexts. This function is generally only useful for queries which are
  * explicitly DBMS-dependent and are unsupported by the query wrappers, such
  * as CREATE TABLE.
  *
  * However, the query wrappers themselves should call this function.
  *
  * @param  $sql        String: SQL query
  * @param  $fname      String: Name of the calling function, for profiling/SHOW PROCESSLIST
  *     comment (you can use __METHOD__ or add some extra info)
  * @param  $tempIgnore Boolean:   Whether to avoid throwing an exception on errors...
  *     maybe best to catch the exception instead?
  * @throws MWException
  * @return boolean|ResultWrapper. true for a successful write query, ResultWrapper object
  *     for a successful read query, or false on failure if $tempIgnore set
  */
 public function query($sql, $fname = '', $tempIgnore = false)
 {
     $isMaster = !is_null($this->getLBInfo('master'));
     if (!Profiler::instance()->isStub()) {
         # generalizeSQL will probably cut down the query to reasonable
         # logging size most of the time. The substr is really just a sanity check.
         if ($isMaster) {
             $queryProf = 'query-m: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query-master';
         } else {
             $queryProf = 'query: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query';
         }
         wfProfileIn($totalProf);
         wfProfileIn($queryProf);
     }
     $this->mLastQuery = $sql;
     if (!$this->mDoneWrites && $this->isWriteQuery($sql)) {
         # Set a flag indicating that writes have been done
         wfDebug(__METHOD__ . ": Writes done: {$sql}\n");
         $this->mDoneWrites = true;
     }
     # Add a comment for easy SHOW PROCESSLIST interpretation
     global $wgUser;
     if (is_object($wgUser) && $wgUser->isItemLoaded('name')) {
         $userName = $wgUser->getName();
         if (mb_strlen($userName) > 15) {
             $userName = mb_substr($userName, 0, 15) . '...';
         }
         $userName = str_replace('/', '', $userName);
     } else {
         $userName = '';
     }
     // Add trace comment to the begin of the sql string, right after the operator.
     // Or, for one-word queries (like "BEGIN" or COMMIT") add it to the end (bug 42598)
     $commentedSql = preg_replace('/\\s|$/', " /* {$fname} {$userName} */ ", $sql, 1);
     # If DBO_TRX is set, start a transaction
     if ($this->mFlags & DBO_TRX && !$this->mTrxLevel && $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK') {
         # Avoid establishing transactions for SHOW and SET statements too -
         # that would delay transaction initializations to once connection
         # is really used by application
         $sqlstart = substr($sql, 0, 10);
         // very much worth it, benchmark certified(tm)
         if (strpos($sqlstart, "SHOW ") !== 0 && strpos($sqlstart, "SET ") !== 0) {
             global $wgDebugDBTransactions;
             if ($wgDebugDBTransactions) {
                 wfDebug("Implicit transaction start.\n");
             }
             $this->begin(__METHOD__ . " ({$fname})");
             $this->mTrxAutomatic = true;
         }
     }
     # Keep track of whether the transaction has write queries pending
     if ($this->mTrxLevel && !$this->mTrxDoneWrites && $this->isWriteQuery($sql)) {
         $this->mTrxDoneWrites = true;
     }
     if ($this->debug()) {
         static $cnt = 0;
         $cnt++;
         $sqlx = substr($commentedSql, 0, 500);
         $sqlx = strtr($sqlx, "\t\n", '  ');
         $master = $isMaster ? 'master' : 'slave';
         wfDebug("Query {$this->mDBname} ({$cnt}) ({$master}): {$sqlx}\n");
     }
     if (istainted($sql) & TC_MYSQL) {
         throw new MWException('Tainted query found');
     }
     $queryId = MWDebug::query($sql, $fname, $isMaster);
     # Do the query and handle errors
     $ret = $this->doQuery($commentedSql);
     MWDebug::queryTime($queryId);
     # Try reconnecting if the connection was lost
     if (false === $ret && $this->wasErrorReissuable()) {
         # Transaction is gone, like it or not
         $this->mTrxLevel = 0;
         $this->mTrxIdleCallbacks = array();
         // cancel
         wfDebug("Connection lost, reconnecting...\n");
         if ($this->ping()) {
             wfDebug("Reconnected\n");
             $sqlx = substr($commentedSql, 0, 500);
             $sqlx = strtr($sqlx, "\t\n", '  ');
             global $wgRequestTime;
             $elapsed = round(microtime(true) - $wgRequestTime, 3);
             if ($elapsed < 300) {
                 # Not a database error to lose a transaction after a minute or two
                 wfLogDBError("Connection lost and reconnected after {$elapsed}s, query: {$sqlx}\n");
             }
             $ret = $this->doQuery($commentedSql);
         } else {
             wfDebug("Failed\n");
         }
     }
     if (false === $ret) {
         $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore);
     }
     if (!Profiler::instance()->isStub()) {
         wfProfileOut($queryProf);
         wfProfileOut($totalProf);
     }
     return $this->resultObject($ret);
 }