From c415a9374872c6235fe822a5e038546522817e3a Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 21 Mar 2017 12:18:47 +0100 Subject: Fix a couple of warnings and notices from error.log --- inc/property.inc.php | 8 ++++---- inc/util.inc.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'inc') diff --git a/inc/property.inc.php b/inc/property.inc.php index b3d8081a..b33e1bff 100644 --- a/inc/property.inc.php +++ b/inc/property.inc.php @@ -146,19 +146,19 @@ class Property public static function getVersionCheckInformation() { - $data = json_decode(self::get('versioncheck-data'), true); - if (isset($data['time']) && $data['time'] + 120 > time()) + $data = json_decode(self::get('versioncheck-data', '[]'), true); + if (isset($data['time']) && $data['time'] + 60 > time()) return $data; $task = Taskmanager::submit('DownloadText', array( 'url' => CONFIG_REMOTE_ML . '/list.php' )); if (!isset($task['id'])) return 'Could not start list download (' . Message::asString() . ')'; - if ($task['statusCode'] !== TASK_FINISHED) { + if (!Taskmanager::isFinished($task)) { $task = Taskmanager::waitComplete($task['id'], 5000); } if ($task['statusCode'] !== TASK_FINISHED || !isset($task['data']['content'])) { - return $task['data']['error']; + return isset($task['data']['error']) ? $task['data']['error'] : 'Timeout'; } $data = json_decode($task['data']['content'], true); $data['time'] = time(); diff --git a/inc/util.inc.php b/inc/util.inc.php index d454d18d..f5e10ebc 100644 --- a/inc/util.inc.php +++ b/inc/util.inc.php @@ -375,7 +375,7 @@ SADFACE; * @param bool $secure true = only use strong random sources * @return string|bool string of requested length, false on error */ - public static function randomBytes($length, $secure) + public static function randomBytes($length, $secure = true) { if (function_exists('random_bytes')) { return random_bytes($length); -- cgit v1.2.3-55-g7522 From 422d95a745d9b177da2d68eb815f3cd8ac42f351 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 21 Mar 2017 14:41:37 +0100 Subject: [inc/Download] Properly return final HTTP status code for redirected requests --- inc/download.inc.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'inc') diff --git a/inc/download.inc.php b/inc/download.inc.php index 51601545..a2054f78 100644 --- a/inc/download.inc.php +++ b/inc/download.inc.php @@ -49,8 +49,8 @@ class Download curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $data = curl_exec($ch); $head = self::getContents($head); - if (preg_match('#^HTTP/\d+\.\d+ (\d+) #', $head, $out)) { - $code = (int) $out[1]; + if (preg_match_all('#^HTTP/\d+\.\d+ (\d+) #m', $head, $out)) { + $code = (int) array_pop($out[1]); } else { $code = 999; } @@ -83,8 +83,8 @@ class Download curl_setopt($ch, CURLOPT_POSTFIELDS, $string); $data = curl_exec($ch); $head = self::getContents($head); - if (preg_match('#^HTTP/\d+\.\d+ (\d+) #', $head, $out)) { - $code = (int) $out[1]; + if (preg_match_all('#^HTTP/\d+\.\d+ (\d+) #m', $head, $out)) { + $code = (int) array_pop($out[1]); } else { $code = 999; } @@ -116,8 +116,8 @@ class Download @unlink($target); return false; } - if (preg_match_all('#\bHTTP/\d+\.\d+ (\d+) #', $head, $out, PREG_SET_ORDER)) { - $code = (int) $out[count($out) - 1][1]; + if (preg_match_all('#^HTTP/\d+\.\d+ (\d+) #m', $head, $out)) { + $code = (int) array_pop($out[1]); } else { $code = '999 ' . curl_error($ch); } -- cgit v1.2.3-55-g7522 From 5337a6f08644b5f080ca3c3f1616c94d13d7565a Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 7 Apr 2017 11:02:19 +0200 Subject: [inc/Database] Add helper function to run INSERT and retrieve keys --- inc/database.inc.php | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'inc') diff --git a/inc/database.inc.php b/inc/database.inc.php index 4a5821f4..ff98f5ee 100644 --- a/inc/database.inc.php +++ b/inc/database.inc.php @@ -132,4 +132,98 @@ class Database return self::$dbh->prepare($query); } + /** + * Insert row into table, returning the generated key. + * This requires the table to have an AUTO_INCREMENT column and + * usually requires the given $uniqueValues to span across a UNIQUE index. + * The code first tries to SELECT the key for the given values without + * inserting first. This means this function is best used for cases + * where you expect that the entry already exists in the table, so + * only one SELECT will run. For all the entries that do not exist, + * an INSERT or INSERT IGNORE is run, depending on whether $additionalValues + * is empty or not. Another reason we don't run the INSERT (IGNORE) first + * is that it will increase the AUTO_INCREMENT value on InnoDB, even when + * no INSERT took place. So if you expect a lot of collisions you might + * use this function to prevent your A_I value from counting up too + * quickly. + * Other than that, this is just a dumb version of running INSERT and then + * getting the LAST_INSERT_ID(), or doing a query for the existing ID in + * case of a key collision. + * + * @param string $table table to insert into + * @param string $aiKey name of the AUTO_INCREMENT column + * @param array $uniqueValues assoc array containing columnName => value mapping + * @param array $additionalValues assoc array containing columnName => value mapping + * @return int[] list of AUTO_INCREMENT values matching the list of $values + */ + public static function insertIgnore($table, $aiKey, $uniqueValues, $additionalValues = false) + { + // Sanity checks + if (array_key_exists($aiKey, $uniqueValues)) { + Util::traceError("$aiKey must not be in \$uniqueValues"); + } + if (is_array($additionalValues) && array_key_exists($aiKey, $additionalValues)) { + Util::traceError("$aiKey must not be in \$additionalValues"); + } + // Simple SELECT first + $selectSql = 'SELECT ' . $aiKey . ' FROM ' . $table . ' WHERE 1'; + foreach ($uniqueValues as $key => $value) { + $selectSql .= ' AND ' . $key . ' = :' . $key; + } + $selectSql .= ' LIMIT 1'; + $res = self::queryFirst($selectSql, $uniqueValues); + if ($res !== false) { + // Exists + if (!empty($additionalValues)) { + // Simulate ON DUPLICATE KEY UPDATE ... + $updateSql = 'UPDATE ' . $table . ' SET '; + $first = true; + foreach ($additionalValues as $key => $value) { + if ($first) { + $first = false; + } else { + $updateSql .= ', '; + } + $updateSql .= $key . ' = :' . $key; + } + $updateSql .= ' WHERE ' . $aiKey . ' = :' . $aiKey; + $additionalValues[$aiKey] = $res[$aiKey]; + Database::exec($updateSql, $additionalValues); + } + return $res[$aiKey]; + } + // Does not exist: + if (empty($additionalValues)) { + $combined =& $uniqueValues; + } else { + $combined = $uniqueValues + $additionalValues; + } + // Aight, try INSERT or INSERT IGNORE + $insertSql = 'INTO ' . $table . ' (' . implode(', ', array_keys($combined)) + . ') VALUES (:' . implode(', :', array_keys($combined)) . ')'; + if (empty($additionalValues)) { + // Simple INSERT IGNORE + $insertSql = 'INSERT IGNORE ' . $insertSql; + } else { + // INSERT ... ON DUPLICATE (in case we have a race) + $insertSql = 'INSERT ' . $insertSql . ' ON DUPLICATE KEY UPDATE '; + $first = true; + foreach ($additionalValues as $key => $value) { + if ($first) { + $first = false; + } else { + $insertSql .= ', '; + } + $insertSql .= $key . ' = VALUES(' . $key . ')'; + } + } + self::exec($insertSql, $combined); + // Insert done, retrieve key again + $res = self::queryFirst($selectSql, $uniqueValues); + if ($res === false) { + Util::traceError('Could not find value in table ' . $table . ' that was just inserted'); + } + return $res[$aiKey]; + } + } -- cgit v1.2.3-55-g7522 From b72e85bf62a7c1f227e4e70b37451a863a0ad136 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 7 Apr 2017 11:03:54 +0200 Subject: [inc/Util] Improve traceError() output --- inc/util.inc.php | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) (limited to 'inc') diff --git a/inc/util.inc.php b/inc/util.inc.php index f5e10ebc..5d1a4563 100644 --- a/inc/util.inc.php +++ b/inc/util.inc.php @@ -21,6 +21,11 @@ class Util exit(1); } Header('HTTP/1.1 500 Internal Server Error'); + if (isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'html') === false ) { + Header('Content-Type: text/plain; charset=utf-8'); + echo 'API ERROR: ', $message, "\n", self::formatBacktracePlain(debug_backtrace()); + exit(0); + } Header('Content-Type: text/html; charset=utf-8'); echo '