summaryrefslogtreecommitdiffstats
path: root/inc
diff options
context:
space:
mode:
authorChristian Hofmaier2017-04-12 14:30:18 +0200
committerChristian Hofmaier2017-04-12 14:30:18 +0200
commit9f27c7cdeb1df2f9c42373f419c6621d4faa71ca (patch)
treee55c6e1d95685df2117401e97f946b962f4e0f47 /inc
parent[permissionmanager] changed description to tooltips (diff)
parent[rebootcontrol] New module for shutting down and rebooting clients (diff)
downloadslx-admin-9f27c7cdeb1df2f9c42373f419c6621d4faa71ca.tar.gz
slx-admin-9f27c7cdeb1df2f9c42373f419c6621d4faa71ca.tar.xz
slx-admin-9f27c7cdeb1df2f9c42373f419c6621d4faa71ca.zip
Merge branches 'master' and 'permission-manager' of git.openslx.org:openslx-ng/slx-admin into permission-manager
Diffstat (limited to 'inc')
-rw-r--r--inc/database.inc.php94
-rw-r--r--inc/download.inc.php12
-rw-r--r--inc/property.inc.php8
-rw-r--r--inc/util.inc.php49
4 files changed, 137 insertions, 26 deletions
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];
+ }
+
}
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);
}
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..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 '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><style>', "\n",
".arg { color: red; background: white; }\n",
@@ -79,19 +84,38 @@ SADFACE;
exit(0);
}
+ private static function formatArgument($arg, $expandArray = true)
+ {
+ if (is_string($arg)) {
+ $arg = "'$arg'";
+ } elseif (is_object($arg)) {
+ $arg = 'instanceof ' . get_class($arg);
+ } elseif (is_array($arg)) {
+ if ($expandArray && count($arg) < 20) {
+ $expanded = '';
+ foreach ($arg as $key => $value) {
+ if (!empty($expanded)) {
+ $expanded .= ', ';
+ }
+ $expanded .= $key . ': ' . self::formatArgument($value, false);
+ if (strlen($expanded) > 200)
+ break;
+ }
+ if (strlen($expanded) <= 200)
+ return '[' . $expanded . ']';
+ }
+ $arg = 'Array(' . count($arg) . ')';
+ }
+ return $arg;
+ }
+
public static function formatBacktraceHtml($trace, $escape = true)
{
$output = '';
foreach ($trace as $idx => $line) {
$args = array();
foreach ($line['args'] as $arg) {
- if (is_string($arg)) {
- $arg = "'$arg'";
- } elseif (is_object($arg)) {
- $arg = 'instanceof ' . get_class($arg);
- } elseif (is_array($arg)) {
- $arg = 'Array(' . count($arg) . ')';
- }
+ $arg = self::formatArgument($arg);
$args[] = '<span class="arg">' . htmlspecialchars($arg) . '</span>';
}
$frame = str_pad('#' . $idx, 3, ' ', STR_PAD_LEFT);
@@ -111,14 +135,7 @@ SADFACE;
foreach ($trace as $idx => $line) {
$args = array();
foreach ($line['args'] as $arg) {
- if (is_string($arg)) {
- $arg = "'$arg'";
- } elseif (is_object($arg)) {
- $arg = 'instanceof ' . get_class($arg);
- } elseif (is_array($arg)) {
- $arg = 'Array(' . count($arg) . ')';
- }
- $args[] = $arg;
+ $args[] = self::formatArgument($arg);
}
$frame = str_pad('#' . $idx, 3, ' ', STR_PAD_LEFT);
$args = implode(', ', $args);
@@ -375,7 +392,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);