Feature: image upload (beta)
This commit is contained in:
parent
9f885f6068
commit
460d608095
@ -36,7 +36,7 @@ abstract class BaseDatabaseTestCase extends PHPUnit_Extensions_Database_TestCase
|
||||
protected $testAccuracy = 10;
|
||||
protected $testProvider = "gps";
|
||||
protected $testComment = "test comment";
|
||||
protected $testImageId = 1;
|
||||
protected $testImage = "1234_1502974402_5d1a1960335cf.jpg";
|
||||
|
||||
// Fixes PostgreSQL: "cannot truncate a table referenced in a foreign key constraint"
|
||||
protected function getSetUpOperation() {
|
||||
|
@ -225,7 +225,7 @@ class ClientAPITest extends UloggerAPITestCase {
|
||||
'accuracy' => $this->testAccuracy,
|
||||
'provider' => $this->testProvider,
|
||||
'comment' => $this->testComment,
|
||||
'imageid' => $this->testImageId
|
||||
'imageid' => $this->testImage
|
||||
],
|
||||
];
|
||||
$response = $this->http->post('/client/index.php', $options);
|
||||
@ -246,11 +246,11 @@ class ClientAPITest extends UloggerAPITestCase {
|
||||
"accuracy" => $this->testAccuracy,
|
||||
"provider" => $this->testProvider,
|
||||
"comment" => $this->testComment,
|
||||
"image_id" => $this->testImageId
|
||||
"image" => $this->testImage
|
||||
];
|
||||
$actual = $this->getConnection()->createQueryTable(
|
||||
"positions",
|
||||
"SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
|
||||
"SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image FROM positions"
|
||||
);
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
}
|
||||
@ -275,7 +275,7 @@ class ClientAPITest extends UloggerAPITestCase {
|
||||
'accuracy' => $this->testAccuracy,
|
||||
'provider' => $this->testProvider,
|
||||
'comment' => $this->testComment,
|
||||
'imageid' => $this->testImageId
|
||||
'imageid' => $this->testImage
|
||||
],
|
||||
];
|
||||
$response = $this->http->post('/client/index.php', $options);
|
||||
@ -306,7 +306,7 @@ class ClientAPITest extends UloggerAPITestCase {
|
||||
'accuracy' => $this->testAccuracy,
|
||||
'provider' => $this->testProvider,
|
||||
'comment' => $this->testComment,
|
||||
'imageid' => $this->testImageId
|
||||
'imageid' => $this->testImage
|
||||
],
|
||||
];
|
||||
|
||||
@ -343,7 +343,7 @@ class ClientAPITest extends UloggerAPITestCase {
|
||||
'accuracy' => $this->testAccuracy,
|
||||
'provider' => $this->testProvider,
|
||||
'comment' => $this->testComment,
|
||||
'imageid' => $this->testImageId
|
||||
'imageid' => $this->testImage
|
||||
],
|
||||
];
|
||||
|
||||
|
@ -88,12 +88,12 @@ class ImportTest extends UloggerAPITestCase {
|
||||
"accuracy" => null,
|
||||
"provider" => "gps",
|
||||
"comment" => null,
|
||||
"image_id" => null
|
||||
"image" => null
|
||||
];
|
||||
$actual = $this->getConnection()->createQueryTable(
|
||||
"positions",
|
||||
"SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude,
|
||||
altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
|
||||
altitude, speed, bearing, accuracy, provider, comment, image FROM positions"
|
||||
);
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
|
||||
@ -110,7 +110,7 @@ class ImportTest extends UloggerAPITestCase {
|
||||
"accuracy" => null,
|
||||
"provider" => "gps",
|
||||
"comment" => null,
|
||||
"image_id" => null
|
||||
"image" => null
|
||||
];
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
}
|
||||
@ -204,12 +204,12 @@ class ImportTest extends UloggerAPITestCase {
|
||||
"accuracy" => null,
|
||||
"provider" => "gps",
|
||||
"comment" => null,
|
||||
"image_id" => null
|
||||
"image" => null
|
||||
];
|
||||
$actual = $this->getConnection()->createQueryTable(
|
||||
"positions",
|
||||
"SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude,
|
||||
altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
|
||||
altitude, speed, bearing, accuracy, provider, comment, image FROM positions"
|
||||
);
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
}
|
||||
@ -304,12 +304,12 @@ class ImportTest extends UloggerAPITestCase {
|
||||
"accuracy" => $this->testAccuracy,
|
||||
"provider" => $this->testProvider,
|
||||
"comment" => null,
|
||||
"image_id" => null
|
||||
"image" => null
|
||||
];
|
||||
$actual = $this->getConnection()->createQueryTable(
|
||||
"positions",
|
||||
"SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude,
|
||||
altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
|
||||
altitude, speed, bearing, accuracy, provider, comment, image FROM positions"
|
||||
);
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
}
|
||||
@ -385,12 +385,12 @@ class ImportTest extends UloggerAPITestCase {
|
||||
"accuracy" => null,
|
||||
"provider" => "gps",
|
||||
"comment" => null,
|
||||
"image_id" => null
|
||||
"image" => null
|
||||
];
|
||||
$actual = $this->getConnection()->createQueryTable(
|
||||
"positions",
|
||||
"SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude,
|
||||
altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
|
||||
altitude, speed, bearing, accuracy, provider, comment, image FROM positions"
|
||||
);
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
}
|
||||
@ -472,12 +472,12 @@ class ImportTest extends UloggerAPITestCase {
|
||||
"accuracy" => null,
|
||||
"provider" => "gps",
|
||||
"comment" => null,
|
||||
"image_id" => null
|
||||
"image" => null
|
||||
];
|
||||
$actual = $this->getConnection()->createQueryTable(
|
||||
"positions",
|
||||
"SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude,
|
||||
altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
|
||||
altitude, speed, bearing, accuracy, provider, comment, image FROM positions"
|
||||
);
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
$expected = [
|
||||
@ -493,7 +493,7 @@ class ImportTest extends UloggerAPITestCase {
|
||||
"accuracy" => null,
|
||||
"provider" => "gps",
|
||||
"comment" => null,
|
||||
"image_id" => null
|
||||
"image" => null
|
||||
];
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
}
|
||||
@ -584,12 +584,12 @@ class ImportTest extends UloggerAPITestCase {
|
||||
"accuracy" => null,
|
||||
"provider" => "gps",
|
||||
"comment" => null,
|
||||
"image_id" => null
|
||||
"image" => null
|
||||
];
|
||||
$actual = $this->getConnection()->createQueryTable(
|
||||
"positions",
|
||||
"SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude,
|
||||
altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
|
||||
altitude, speed, bearing, accuracy, provider, comment, image FROM positions"
|
||||
);
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
$expected = [
|
||||
@ -605,7 +605,7 @@ class ImportTest extends UloggerAPITestCase {
|
||||
"accuracy" => null,
|
||||
"provider" => "gps",
|
||||
"comment" => null,
|
||||
"image_id" => null
|
||||
"image" => null
|
||||
];
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
}
|
||||
|
@ -11,15 +11,15 @@ class PositionTest extends UloggerDatabaseTestCase {
|
||||
$trackId = $this->addTestTrack($userId);
|
||||
$this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
|
||||
|
||||
$posId = uPosition::add($userId, $trackId + 1, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
|
||||
$posId = uPosition::add($userId, $trackId + 1, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage);
|
||||
$this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
|
||||
$this->assertFalse($posId, "Adding position with nonexistant track should fail");
|
||||
|
||||
$posId = uPosition::add($userId + 1, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
|
||||
$posId = uPosition::add($userId + 1, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage);
|
||||
$this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
|
||||
$this->assertFalse($posId, "Adding position with wrong user should fail");
|
||||
|
||||
$posId = uPosition::add($userId, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
|
||||
$posId = uPosition::add($userId, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage);
|
||||
$this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count");
|
||||
$expected = [
|
||||
"id" => $posId,
|
||||
@ -34,11 +34,11 @@ class PositionTest extends UloggerDatabaseTestCase {
|
||||
"accuracy" => $this->testAccuracy,
|
||||
"provider" => $this->testProvider,
|
||||
"comment" => $this->testComment,
|
||||
"image_id" => $this->testImageId
|
||||
"image" => $this->testImage
|
||||
];
|
||||
$actual = $this->getConnection()->createQueryTable(
|
||||
"positions",
|
||||
"SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
|
||||
"SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image FROM positions"
|
||||
);
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
|
||||
|
@ -41,16 +41,16 @@ class TrackTest extends UloggerDatabaseTestCase {
|
||||
$this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
|
||||
|
||||
$track = new uTrack($trackId + 1);
|
||||
$posId = $track->addPosition($userId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
|
||||
$posId = $track->addPosition($userId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage);
|
||||
$this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
|
||||
$this->assertFalse($posId, "Adding position with nonexistant track should fail");
|
||||
|
||||
$track = new uTrack($trackId);
|
||||
$posId = $track->addPosition($userId2, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
|
||||
$posId = $track->addPosition($userId2, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage);
|
||||
$this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
|
||||
$this->assertFalse($posId, "Adding position with wrong user should fail");
|
||||
|
||||
$posId = $track->addPosition($userId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
|
||||
$posId = $track->addPosition($userId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage);
|
||||
$this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count");
|
||||
$expected = [
|
||||
"id" => $posId,
|
||||
@ -65,11 +65,11 @@ class TrackTest extends UloggerDatabaseTestCase {
|
||||
"accuracy" => $this->testAccuracy,
|
||||
"provider" => $this->testProvider,
|
||||
"comment" => $this->testComment,
|
||||
"image_id" => $this->testImageId
|
||||
"image" => $this->testImage
|
||||
];
|
||||
$actual = $this->getConnection()->createQueryTable(
|
||||
"positions",
|
||||
"SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
|
||||
"SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image FROM positions"
|
||||
);
|
||||
$this->assertTableContains($expected, $actual, "Wrong actual table data");
|
||||
|
||||
|
@ -55,7 +55,7 @@
|
||||
exitWithError("Unauthorized");
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
switch ($action) {
|
||||
// action: authorize
|
||||
case "auth":
|
||||
$login = uUtils::postString('user');
|
||||
@ -111,16 +111,21 @@
|
||||
$accuracy = uUtils::postInt('accuracy');
|
||||
$provider = uUtils::postString('provider');
|
||||
$comment = uUtils::postString('comment');
|
||||
$imageId = uUtils::postInt('imageid');
|
||||
$imageMeta = uUtils::requestFile('image');
|
||||
$trackId = uUtils::postInt('trackid');
|
||||
|
||||
if (!is_float($lat) || !is_float($lon) || !is_int($timestamp) || !is_int($trackId)) {
|
||||
exitWithError("Missing required parameter");
|
||||
}
|
||||
|
||||
$image = null;
|
||||
if (!empty($imageMeta)) {
|
||||
$image = uUpload::add($imageMeta, $trackId);
|
||||
}
|
||||
|
||||
require_once(ROOT_DIR . "/helpers/position.php");
|
||||
$positionId = uPosition::add($auth->user->id, $trackId,
|
||||
$timestamp, $lat, $lon, $altitude, $speed, $bearing, $accuracy, $provider, $comment, $imageId);
|
||||
$timestamp, $lat, $lon, $altitude, $speed, $bearing, $accuracy, $provider, $comment, $image);
|
||||
|
||||
if ($positionId === false) {
|
||||
exitWithError("Server error");
|
||||
|
@ -18,7 +18,8 @@
|
||||
*/
|
||||
|
||||
require_once(ROOT_DIR . "/helpers/db.php");
|
||||
require_once(ROOT_DIR . "/helpers/track.php");
|
||||
require_once(ROOT_DIR . "/helpers/track.php");
|
||||
require_once(ROOT_DIR . "/helpers/upload.php");
|
||||
|
||||
/**
|
||||
* Positions handling
|
||||
@ -51,9 +52,9 @@
|
||||
/** @param String Provider */
|
||||
public $provider;
|
||||
/** @param String Comment */
|
||||
public $comment; // not used yet
|
||||
/** @param int Image id */
|
||||
public $imageId; // not used yet
|
||||
public $comment;
|
||||
/** @param String Image path */
|
||||
public $image;
|
||||
|
||||
public $isValid = false;
|
||||
|
||||
@ -66,7 +67,7 @@
|
||||
if (!empty($positionId)) {
|
||||
$query = "SELECT p.id, " . self::db()->unix_timestamp('p.time') . " AS tstamp, p.user_id, p.track_id,
|
||||
p.latitude, p.longitude, p.altitude, p.speed, p.bearing, p.accuracy, p.provider,
|
||||
p.comment, p.image_id, u.login, t.name
|
||||
p.comment, p.image, u.login, t.name
|
||||
FROM " . self::db()->table('positions') . " p
|
||||
LEFT JOIN " . self::db()->table('users') . " u ON (p.user_id = u.id)
|
||||
LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id)
|
||||
@ -104,12 +105,12 @@
|
||||
* @param int $accuracy Optional
|
||||
* @param string $provider Optional
|
||||
* @param string $comment Optional
|
||||
* @param int $imageId Optional
|
||||
* @param int $image Optional
|
||||
* @return int|bool New position id in database, false on error
|
||||
*/
|
||||
public static function add($userId, $trackId, $timestamp, $lat, $lon,
|
||||
$altitude = NULL, $speed = NULL, $bearing = NULL, $accuracy = NULL,
|
||||
$provider = NULL, $comment = NULL, $imageId = NULL) {
|
||||
$provider = NULL, $comment = NULL, $image = NULL) {
|
||||
$positionId = false;
|
||||
if (is_numeric($lat) && is_numeric($lon) && is_numeric($timestamp) && is_numeric($userId) && is_numeric($trackId)) {
|
||||
$track = new uTrack($trackId);
|
||||
@ -118,11 +119,11 @@
|
||||
$table = self::db()->table('positions');
|
||||
$query = "INSERT INTO $table
|
||||
(user_id, track_id,
|
||||
time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id)
|
||||
time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image)
|
||||
VALUES (?, ?, " . self::db()->from_unixtime('?') . ", ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = self::db()->prepare($query);
|
||||
$params = [ $userId, $trackId,
|
||||
$timestamp, $lat, $lon, $altitude, $speed, $bearing, $accuracy, $provider, $comment, $imageId ];
|
||||
$timestamp, $lat, $lon, $altitude, $speed, $bearing, $accuracy, $provider, $comment, $image ];
|
||||
$stmt->execute($params);
|
||||
$positionId = self::db()->lastInsertId("${table}_id_seq");
|
||||
} catch (PDOException $e) {
|
||||
@ -151,6 +152,7 @@
|
||||
$where .= " AND track_id = ?";
|
||||
$args[] = $trackId;
|
||||
}
|
||||
self::removeImages($userId, $trackId);
|
||||
try {
|
||||
$query = "DELETE FROM " . self::db()->table('positions') . " $where";
|
||||
$stmt = self::db()->prepare($query);
|
||||
@ -181,7 +183,7 @@
|
||||
}
|
||||
$query = "SELECT p.id, " . self::db()->unix_timestamp('p.time') . " AS tstamp, p.user_id, p.track_id,
|
||||
p.latitude, p.longitude, p.altitude, p.speed, p.bearing, p.accuracy, p.provider,
|
||||
p.comment, p.image_id, u.login, t.name
|
||||
p.comment, p.image, u.login, t.name
|
||||
FROM " . self::db()->table('positions') . " p
|
||||
LEFT JOIN " . self::db()->table('users') . " u ON (p.user_id = u.id)
|
||||
LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id)
|
||||
@ -205,7 +207,7 @@
|
||||
public static function getLastAllUsers() {
|
||||
$query = "SELECT p.id, " . self::db()->unix_timestamp('p.time') . " AS tstamp, p.user_id, p.track_id,
|
||||
p.latitude, p.longitude, p.altitude, p.speed, p.bearing, p.accuracy, p.provider,
|
||||
p.comment, p.image_id, u.login, t.name
|
||||
p.comment, p.image, u.login, t.name
|
||||
FROM " . self::db()->table('positions') . " p
|
||||
LEFT JOIN " . self::db()->table('users') . " u ON (p.user_id = u.id)
|
||||
LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id)
|
||||
@ -224,6 +226,7 @@
|
||||
} catch (PDOException $e) {
|
||||
// TODO: handle exception
|
||||
syslog(LOG_ERR, $e->getMessage());
|
||||
$positionsArr = false;
|
||||
}
|
||||
return $positionsArr;
|
||||
}
|
||||
@ -234,17 +237,17 @@
|
||||
* @param int $userId Optional limit to given user id
|
||||
* @param int $trackId Optional limit to given track id
|
||||
* @param int $afterId Optional limit to positions with id greater then given id
|
||||
* @return array|bool Array of uPosition positions, false on error
|
||||
* @param array $rules Optional rules
|
||||
* @return uPosition[]|bool Array of uPosition positions, false on error
|
||||
*/
|
||||
public static function getAll($userId = NULL, $trackId = NULL, $afterId = NULL) {
|
||||
$rules = [];
|
||||
public static function getAll($userId = NULL, $trackId = NULL, $afterId = NULL, $rules = []) {
|
||||
if (!empty($userId)) {
|
||||
$rules[] = "p.user_id = " . self::db()->quote($userId);
|
||||
}
|
||||
if (!empty($trackId)) {
|
||||
$rules[] = "p.track_id = " . self::db()->quote($trackId);
|
||||
}
|
||||
if (!empty($trackId)) {
|
||||
if (!empty($afterId)) {
|
||||
$rules[] = "p.id > " . self::db()->quote($afterId);
|
||||
}
|
||||
if (!empty($rules)) {
|
||||
@ -254,7 +257,7 @@
|
||||
}
|
||||
$query = "SELECT p.id, " . self::db()->unix_timestamp('p.time') . " AS tstamp, p.user_id, p.track_id,
|
||||
p.latitude, p.longitude, p.altitude, p.speed, p.bearing, p.accuracy, p.provider,
|
||||
p.comment, p.image_id, u.login, t.name
|
||||
p.comment, p.image, u.login, t.name
|
||||
FROM " . self::db()->table('positions') . " p
|
||||
LEFT JOIN " . self::db()->table('users') . " u ON (p.user_id = u.id)
|
||||
LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id)
|
||||
@ -269,10 +272,53 @@
|
||||
} catch (PDOException $e) {
|
||||
// TODO: handle exception
|
||||
syslog(LOG_ERR, $e->getMessage());
|
||||
$positionsArr = false;
|
||||
}
|
||||
return $positionsArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of all positions with image
|
||||
*
|
||||
* @param int $userId Optional limit to given user id
|
||||
* @param int $trackId Optional limit to given track id
|
||||
* @param int $afterId Optional limit to positions with id greater then given id
|
||||
* @param array $rules Optional rules
|
||||
* @return uPosition[]|bool Array of uPosition positions, false on error
|
||||
*/
|
||||
public static function getAllWithImage($userId = NULL, $trackId = NULL, $afterId = NULL, $rules = []) {
|
||||
$rules[] = "p.image IS NOT NULL";
|
||||
return self::getAll($userId, $trackId, $afterId, $rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all user's uploads, optionally limit to given track
|
||||
*
|
||||
* @param int $userId User id
|
||||
* @param int $trackId Optional track id
|
||||
* @return bool True if success, false otherwise
|
||||
*/
|
||||
public static function removeImages($userId, $trackId = NULL) {
|
||||
if (($positions = uPosition::getAllWithImage($userId, $trackId)) !== false) {
|
||||
/** @var uUpload $position */
|
||||
foreach ($positions as $position) {
|
||||
try {
|
||||
$query = "UPDATE " . self::db()->table('positions') . "
|
||||
SET image = NULL WHERE id = ?";
|
||||
$stmt = self::db()->prepare($query);
|
||||
$stmt->execute([ $position->id ]);
|
||||
// ignore unlink errors
|
||||
uUpload::delete($position->image);
|
||||
} catch (PDOException $e) {
|
||||
// TODO: handle exception
|
||||
syslog(LOG_ERR, $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate distance to target point using haversine formula
|
||||
*
|
||||
@ -322,7 +368,7 @@
|
||||
$position->accuracy = $row['accuracy'];
|
||||
$position->provider = $row['provider'];
|
||||
$position->comment = $row['comment'];
|
||||
$position->imageId = $row['image_id'];
|
||||
$position->image = $row['image'];
|
||||
$position->isValid = true;
|
||||
return $position;
|
||||
}
|
||||
@ -350,7 +396,7 @@
|
||||
$stmt->bindColumn('accuracy', $this->accuracy, PDO::PARAM_INT);
|
||||
$stmt->bindColumn('provider', $this->provider);
|
||||
$stmt->bindColumn('comment', $this->comment);
|
||||
$stmt->bindColumn('image_id', $this->imageId, PDO::PARAM_INT);
|
||||
$stmt->bindColumn('image', $this->image);
|
||||
$stmt->bindColumn('login', $this->userLogin);
|
||||
$stmt->bindColumn('name', $this->trackName);
|
||||
if ($stmt->fetch(PDO::FETCH_BOUND)) {
|
||||
|
166
helpers/upload.php
Normal file
166
helpers/upload.php
Normal file
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* μlogger
|
||||
*
|
||||
* Copyright(C) 2019 Bartek Fabiszewski (www.fabiszewski.net)
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
require_once(ROOT_DIR . "/helpers/db.php");
|
||||
require_once(ROOT_DIR . "/helpers/utils.php");
|
||||
|
||||
/**
|
||||
* Uploaded files
|
||||
*/
|
||||
class uUpload {
|
||||
|
||||
const META_TYPE = "type";
|
||||
const META_NAME = "name";
|
||||
const META_TMP_NAME = "tmp_name";
|
||||
const META_ERROR = "error";
|
||||
const META_SIZE = "size";
|
||||
public static $uploadDir = ROOT_DIR . "/uploads/";
|
||||
private static $filePattern = "[a-z0-9_.]{20,}";
|
||||
private static $mimeMap = [];
|
||||
|
||||
/**
|
||||
* @return string[] Mime to extension mapping
|
||||
*/
|
||||
private static function getMimeMap() {
|
||||
if (empty(self::$mimeMap)) {
|
||||
self::$mimeMap["image/jpeg"] = "jpg";
|
||||
self::$mimeMap["image/x-ms-bmp"] = "bmp";
|
||||
self::$mimeMap["image/gif"] = "gif";
|
||||
self::$mimeMap["image/png"] = "png";
|
||||
}
|
||||
return self::$mimeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is mime accepted type
|
||||
* @param string $mime Mime type
|
||||
* @return bool True if known
|
||||
*/
|
||||
private static function isKnownMime($mime) {
|
||||
return array_key_exists($mime, self::getMimeMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file extension for given mime
|
||||
* @param $mime
|
||||
* @return string|null Extension or NULL if not found
|
||||
*/
|
||||
private static function getExtension($mime) {
|
||||
if (self::isKnownMime($mime)) {
|
||||
return self::getMimeMap()[$mime];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save file to uploads, basic sanitizing
|
||||
* @param array $uploaded File meta array from $_FILES[]
|
||||
* @param int $trackId
|
||||
* @return string|NULL Unique file name, null on error
|
||||
*/
|
||||
public static function add($uploaded, $trackId) {
|
||||
try {
|
||||
$fileMeta = self::sanitizeUpload($uploaded);
|
||||
} catch (Exception $e) {
|
||||
syslog(LOG_ERR, $e->getMessage());
|
||||
// save exception to txt file as image replacement?
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$extension = self::getExtension($fileMeta[self::META_TYPE]);
|
||||
|
||||
do {
|
||||
$fileName = uniqid("{$trackId}_") . ".$extension";
|
||||
} while (file_exists(self::$uploadDir . $fileName));
|
||||
if (move_uploaded_file($fileMeta[self::META_TMP_NAME], self::$uploadDir . $fileName)) {
|
||||
return $fileName;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete upload from database and filesystem
|
||||
* @param String $path File relative path
|
||||
* @return bool False if file exists but can't be unlinked
|
||||
*/
|
||||
public static function delete($path) {
|
||||
$ret = true;
|
||||
if (preg_match(self::$filePattern, $path)) {
|
||||
$path = self::$uploadDir . $path;
|
||||
if (file_exists($path)) {
|
||||
$ret = unlink($path);
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fileMeta File meta array from $_FILES[]
|
||||
* @param boolean $checkMime Check with known mime types
|
||||
* @return array File metadata array
|
||||
* @throws ErrorException Internal server exception
|
||||
* @throws Exception File upload exception
|
||||
*/
|
||||
public static function sanitizeUpload($fileMeta, $checkMime = true) {
|
||||
if (!isset($fileMeta) ||
|
||||
!isset($fileMeta[self::META_NAME]) || !isset($fileMeta[self::META_TYPE]) ||
|
||||
!isset($fileMeta[self::META_SIZE]) || !isset($fileMeta[self::META_TMP_NAME])) {
|
||||
$message = "no uploaded file";
|
||||
$lastErr = error_get_last();
|
||||
if (!empty($lastErr)) {
|
||||
$message = $lastErr["message"];
|
||||
}
|
||||
throw new ErrorException($message);
|
||||
}
|
||||
|
||||
$uploadErrors = [];
|
||||
$uploadErrors[UPLOAD_ERR_INI_SIZE] = "Uploaded file exceeds the upload_max_filesize directive in php.ini";
|
||||
$uploadErrors[UPLOAD_ERR_FORM_SIZE] = "Uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form";
|
||||
$uploadErrors[UPLOAD_ERR_PARTIAL] = "File was only partially uploaded";
|
||||
$uploadErrors[UPLOAD_ERR_NO_FILE] = "No file was uploaded";
|
||||
$uploadErrors[UPLOAD_ERR_NO_TMP_DIR] = "Missing a temporary folder";
|
||||
$uploadErrors[UPLOAD_ERR_CANT_WRITE] = "Failed to write file to disk";
|
||||
$uploadErrors[UPLOAD_ERR_EXTENSION] = "A PHP extension stopped file upload";
|
||||
|
||||
$file = NULL;
|
||||
$fileError = isset($fileMeta[self::META_ERROR]) ? $fileMeta[self::META_ERROR] : UPLOAD_ERR_OK;
|
||||
if ($fileMeta[self::META_SIZE] > uUtils::getUploadMaxSize() && $fileError == UPLOAD_ERR_OK) {
|
||||
$fileError = UPLOAD_ERR_FORM_SIZE;
|
||||
}
|
||||
if ($fileError == UPLOAD_ERR_OK) {
|
||||
$file = $fileMeta[self::META_TMP_NAME];
|
||||
} else {
|
||||
$message = "Unknown error";
|
||||
if (isset($uploadErrors[$fileError])) {
|
||||
$message = $uploadErrors[$fileError];
|
||||
}
|
||||
$message .= " ($fileError)";
|
||||
throw new Exception($message);
|
||||
}
|
||||
|
||||
if (!$file || !file_exists($file)) {
|
||||
throw new ErrorException("File not found");
|
||||
}
|
||||
if ($checkMime && !self::isKnownMime($fileMeta[self::META_TYPE])) {
|
||||
throw new Exception("Unsupported mime type");
|
||||
}
|
||||
return $fileMeta;
|
||||
}
|
||||
}
|
@ -165,6 +165,27 @@
|
||||
return self::requestInt($name, $default, INPUT_GET);
|
||||
}
|
||||
|
||||
public static function requestFile($name, $default = NULL) {
|
||||
if (isset($_FILES[$name])) {
|
||||
$files = $_FILES[$name];
|
||||
if (isset($files["name"]) && isset($files["type"]) && isset($files["size"]) && isset($files["tmp_name"])) {
|
||||
return $_FILES[$name];
|
||||
}
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Input name
|
||||
* @param boolean $checkMime Optionally check mime with known types
|
||||
* @return array File metadata array
|
||||
* @throws Exception Upload exception
|
||||
* @throws ErrorException Internal server exception
|
||||
*/
|
||||
public static function requireFile($name, $checkMime = false) {
|
||||
return uUpload::sanitizeUpload($_FILES[$name], $checkMime);
|
||||
}
|
||||
|
||||
private static function requestString($name, $default, $type) {
|
||||
if (is_string(($val = self::requestValue($name, $default, $type)))) {
|
||||
return trim($val);
|
||||
|
@ -208,7 +208,7 @@ function getQueries($dbDriver) {
|
||||
`accuracy` int(11) DEFAULT NULL,
|
||||
`provider` varchar(100) DEFAULT NULL,
|
||||
`comment` varchar(255) DEFAULT NULL,
|
||||
`image_id` int(11) DEFAULT NULL,
|
||||
`image` varchar(100) DEFAULT NULL,
|
||||
INDEX `idx_track_id` (`track_id`),
|
||||
INDEX `idx_user_id` (`user_id`),
|
||||
FOREIGN KEY(`user_id`) REFERENCES `$tUsers`(`id`),
|
||||
@ -249,7 +249,7 @@ function getQueries($dbDriver) {
|
||||
accuracy INT DEFAULT NULL,
|
||||
provider VARCHAR(100) DEFAULT NULL,
|
||||
comment VARCHAR(255) DEFAULT NULL,
|
||||
image_id INT DEFAULT NULL,
|
||||
image VARCHAR(100) DEFAULT NULL,
|
||||
FOREIGN KEY(user_id) REFERENCES $tUsers(id),
|
||||
FOREIGN KEY(track_id) REFERENCES $tTracks(id)
|
||||
)";
|
||||
@ -289,7 +289,7 @@ function getQueries($dbDriver) {
|
||||
`accuracy` integer DEFAULT NULL,
|
||||
`provider` varchar(100) DEFAULT NULL,
|
||||
`comment` varchar(255) DEFAULT NULL,
|
||||
`image_id` integer DEFAULT NULL,
|
||||
`image` varchar(100) DEFAULT NULL,
|
||||
FOREIGN KEY(`user_id`) REFERENCES `$tUsers`(`id`),
|
||||
FOREIGN KEY(`track_id`) REFERENCES `$tTracks`(`id`)
|
||||
)";
|
||||
|
@ -56,7 +56,7 @@ CREATE TABLE positions (
|
||||
accuracy int DEFAULT NULL,
|
||||
provider varchar(100) DEFAULT NULL,
|
||||
comment varchar(255) DEFAULT NULL,
|
||||
image_id int DEFAULT NULL,
|
||||
image varchar(100) DEFAULT NULL,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id),
|
||||
FOREIGN KEY(track_id) REFERENCES tracks(id)
|
||||
);
|
||||
|
@ -55,7 +55,7 @@ CREATE TABLE `positions` (
|
||||
`accuracy` int(11) DEFAULT NULL,
|
||||
`provider` varchar(100) DEFAULT NULL,
|
||||
`comment` varchar(255) DEFAULT NULL,
|
||||
`image_id` int(11) DEFAULT NULL,
|
||||
`image` varchar(100) DEFAULT NULL,
|
||||
INDEX `idx_ptrack_id` (`track_id`),
|
||||
INDEX `index_puser_id` (`user_id`),
|
||||
FOREIGN KEY(`user_id`) REFERENCES `users`(`id`),
|
||||
|
@ -52,7 +52,7 @@ CREATE TABLE `positions` (
|
||||
`accuracy` integer DEFAULT NULL,
|
||||
`provider` varchar(100) DEFAULT NULL,
|
||||
`comment` varchar(255) DEFAULT NULL,
|
||||
`image_id` integer DEFAULT NULL,
|
||||
`image` varchar(100) DEFAULT NULL,
|
||||
FOREIGN KEY(`user_id`) REFERENCES `users`(`id`),
|
||||
FOREIGN KEY(`track_id`) REFERENCES `tracks`(`id`)
|
||||
);
|
||||
|
1
uploads/README
Normal file
1
uploads/README
Normal file
@ -0,0 +1 @@
|
||||
This folder is for uploaded images. It should be writable by PHP.
|
@ -56,28 +56,30 @@ $xml->startDocument("1.0");
|
||||
$xml->setIndent(true);
|
||||
$xml->startElement('root');
|
||||
|
||||
foreach ($positionsArr as $position) {
|
||||
/** @var uPosition $prevPosition */
|
||||
$xml->startElement("position");
|
||||
$xml->writeAttribute("id", $position->id);
|
||||
$xml->writeElement("latitude", $position->latitude);
|
||||
$xml->writeElement("longitude", $position->longitude);
|
||||
$xml->writeElement("altitude", ($position->altitude) ? round($position->altitude) : $position->altitude);
|
||||
$xml->writeElement("speed", $position->speed);
|
||||
$xml->writeElement("bearing", $position->bearing);
|
||||
$xml->writeElement("timestamp", $position->timestamp);
|
||||
$xml->writeElement("accuracy", $position->accuracy);
|
||||
$xml->writeElement("provider", $position->provider);
|
||||
$xml->writeElement("comments", $position->comment);
|
||||
$xml->writeElement("username", $position->userLogin);
|
||||
$xml->writeElement("trackid", $position->trackId);
|
||||
$xml->writeElement("trackname", $position->trackName);
|
||||
$distance = !$last && isset($prevPosition) ? $position->distanceTo($prevPosition) : 0;
|
||||
$xml->writeElement("distance", round($distance));
|
||||
$seconds = !$last && isset($prevPosition) ? $position->secondsTo($prevPosition) : 0;
|
||||
$xml->writeElement("seconds", $seconds);
|
||||
$xml->endElement();
|
||||
$prevPosition = $position;
|
||||
if (!empty($positionsArr)) {
|
||||
foreach ($positionsArr as $position) {
|
||||
/** @var uPosition $prevPosition */
|
||||
$xml->startElement("position");
|
||||
$xml->writeAttribute("id", $position->id);
|
||||
$xml->writeElement("latitude", $position->latitude);
|
||||
$xml->writeElement("longitude", $position->longitude);
|
||||
$xml->writeElement("altitude", ($position->altitude) ? round($position->altitude) : $position->altitude);
|
||||
$xml->writeElement("speed", $position->speed);
|
||||
$xml->writeElement("bearing", $position->bearing);
|
||||
$xml->writeElement("timestamp", $position->timestamp);
|
||||
$xml->writeElement("accuracy", $position->accuracy);
|
||||
$xml->writeElement("provider", $position->provider);
|
||||
$xml->writeElement("comments", $position->comment);
|
||||
$xml->writeElement("username", $position->userLogin);
|
||||
$xml->writeElement("trackid", $position->trackId);
|
||||
$xml->writeElement("trackname", $position->trackName);
|
||||
$distance = !$last && isset($prevPosition) ? $position->distanceTo($prevPosition) : 0;
|
||||
$xml->writeElement("distance", round($distance));
|
||||
$seconds = !$last && isset($prevPosition) ? $position->secondsTo($prevPosition) : 0;
|
||||
$xml->writeElement("seconds", $seconds);
|
||||
$xml->endElement();
|
||||
$prevPosition = $position;
|
||||
}
|
||||
}
|
||||
|
||||
$xml->endElement();
|
||||
|
@ -41,40 +41,23 @@ if (!$auth->isAuthenticated()) {
|
||||
uUtils::exitWithError($lang["private"]);
|
||||
}
|
||||
|
||||
if (!isset($_FILES["gpx"])) {
|
||||
try {
|
||||
$fileMeta = uUtils::requireFile("gpx");
|
||||
} catch (ErrorException $ee) {
|
||||
$message = $lang["servererror"];
|
||||
$lastErr = error_get_last();
|
||||
if (!empty($lastErr)) {
|
||||
$message .= ": " . $lastErr["message"];
|
||||
} else {
|
||||
$message .= ": no uploaded file";
|
||||
}
|
||||
$message .= ": {$ee->getMessage()}";
|
||||
uUtils::exitWithError($message);
|
||||
}
|
||||
|
||||
$gpxFile = NULL;
|
||||
$gpxUpload = $_FILES["gpx"];
|
||||
$uploadErr = $gpxUpload["error"];
|
||||
if ($gpxUpload["size"] > uUtils::getUploadMaxSize() && $uploadErr == UPLOAD_ERR_OK) {
|
||||
$uploadErr = UPLOAD_ERR_FORM_SIZE;
|
||||
}
|
||||
if ($uploadErr == UPLOAD_ERR_OK) {
|
||||
$gpxFile = $gpxUpload["tmp_name"];
|
||||
$gpxName = basename($gpxUpload["name"]);
|
||||
} else {
|
||||
} catch (Exception $e) {
|
||||
$message = $lang["iuploadfailure"];
|
||||
if (isset($uploadErrors[$uploadErr])) {
|
||||
$message .= ": " . $uploadErrors[$uploadErr];
|
||||
}
|
||||
$message .= " ($uploadErr)";
|
||||
$message .= ": {$ee->getMessage()}";
|
||||
uUtils::exitWithError($message);
|
||||
}
|
||||
|
||||
$gpx = false;
|
||||
$gpxFile = $fileMeta[uUpload::META_TMP_NAME];
|
||||
$gpxName = basename($fileMeta[uUpload::META_NAME]);
|
||||
libxml_use_internal_errors(true);
|
||||
if ($gpxFile && file_exists($gpxFile)) {
|
||||
$gpx = simplexml_load_file($gpxFile);
|
||||
}
|
||||
$gpx = simplexml_load_file($gpxFile);
|
||||
unlink($gpxFile);
|
||||
|
||||
if ($gpx === false) {
|
||||
$message = $lang["iparsefailure"];
|
||||
@ -115,6 +98,7 @@ foreach ($gpx->trk as $trk) {
|
||||
}
|
||||
$time = isset($point->time) ? strtotime($point->time) : 1;
|
||||
$altitude = isset($point->ele) ? (double) $point->ele : NULL;
|
||||
$comment = isset($point->desc) && !empty($point->desc) ? (string) $point->desc : NULL;
|
||||
$speed = NULL;
|
||||
$bearing = NULL;
|
||||
$accuracy = NULL;
|
||||
@ -129,7 +113,7 @@ foreach ($gpx->trk as $trk) {
|
||||
}
|
||||
$ret = $track->addPosition($auth->user->id,
|
||||
$time, (double) $point["lat"], (double) $point["lon"], $altitude,
|
||||
$speed, $bearing, $accuracy, $provider, NULL, NULL);
|
||||
$speed, $bearing, $accuracy, $provider, $comment, NULL);
|
||||
if ($ret === false) {
|
||||
$track->delete();
|
||||
uUtils::exitWithError($lang["servererror"]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user