Skip to content

Commit c3ea2cd

Browse files
committed
Push the first release candidate.
1 parent e0cee17 commit c3ea2cd

File tree

3 files changed

+173
-2
lines changed

3 files changed

+173
-2
lines changed

README.md

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,33 @@
1-
# server-php
2-
PhotoBackup server implementation in PHP
1+
# PhotoBackup PHP server
2+
3+
A minimal PhotoBackup API endpoint developed in PHP.
4+
5+
## Goals
6+
7+
1. **Easy to run.** Minimal configuration and the widest possible server
8+
compatibility make this PhotoBackup implementation a great starting point!
9+
10+
2. **Easy to review.** All the code is extensively described through [PSR-5][]
11+
DocComments and should be easy to read along.
12+
13+
[PSR-5]: https://github.com/phpDocumentor/fig-standards/tree/master/proposed
14+
15+
## Setting up
16+
17+
1. Download the latest release from GitHub:
18+
19+
https://github.com/PhotoBackup/server-php/releases/latest
20+
21+
2. Open `index.php` and change the value of `$Password` to the password you want
22+
to use for PhotoBackup.
23+
24+
3. Upload `index.php` and the `photos` folder to your web host.
25+
26+
4. Configure the server address in your PhotoBackup client to match the URL for
27+
your `index.php`-file. E.g. `http://example.com/photobackup/index.php`.
28+
29+
## License
30+
31+
The PhotoBackup PHP server is licensed under the OSI version of the MIT license.
32+
It lets you do anything with the code as long as proper attribution is given.
33+
Please see LICENSE.

index.php

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
/**
3+
* A minimal PhotoBackup API endpoint developed in PHP.
4+
*
5+
* @version 1.0.0-rc.1
6+
* @author Martijn van der Ven <[email protected]>
7+
* @copyright 2015 Martijn van der Ven
8+
* @license http://opensource.org/licenses/MIT The MIT License
9+
*/
10+
11+
/**
12+
* The password required to upload to this server.
13+
*
14+
* The password is currently stored as clear text here. PHP code is not normally
15+
* readable by third-parties so this should be safe enough. Many applications
16+
* store database credentials in this way as well. A secondary and safer way is
17+
* being considered for the next version.
18+
*
19+
* @global string $Password A string (encapsulated by quotes).
20+
*/
21+
$Password = 'example';
22+
23+
/**
24+
* The directory where files should be uploaded to.
25+
*
26+
* This directory path is relative to this index.php file and should not end
27+
* with a /. It should point to an existing directory on the server.
28+
*
29+
* @global string $MediaRoot A string (encapsulated by quotes).
30+
*/
31+
$MediaRoot = 'photos';
32+
33+
// -----------------------------------------------------------------------------
34+
// NO CONFIGURATION NECCESSARY BEYOND THIS POINT.
35+
// -----------------------------------------------------------------------------
36+
37+
/**
38+
* Establish what HTTP version is being used by the server.
39+
*/
40+
if (isset($_SERVER['SERVER_PROTOCOL'])) {
41+
$protocol = $_SERVER['SERVER_PROTOCOL'];
42+
} else {
43+
$protocol = 'HTTP/1.0';
44+
}
45+
46+
/**
47+
* Find out if the client is requesting the test page.
48+
*/
49+
$request = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
50+
$testing = substr($request, -5) === '/test';
51+
52+
/**
53+
* If no data has been POSTed to the server and the client did not request the
54+
* test page, exit imidiately.
55+
*/
56+
if (empty($_POST) && !$testing) {
57+
exit();
58+
}
59+
60+
/**
61+
* If the client did not submit a password, or the submitted password did not
62+
* match this server's password, exit with HTTP code 403.
63+
*/
64+
if (
65+
!isset($_POST['password']) ||
66+
$_POST['password'] !== hash('sha512', $Password)
67+
) {
68+
header($protocol . ' 403 Forbidden');
69+
exit();
70+
}
71+
72+
/**
73+
* If the upload destination folder does not exist or is not writable by PHP,
74+
* exit with HTTP code 500.
75+
*/
76+
if (
77+
!file_exists($MediaRoot) ||
78+
!is_dir($MediaRoot) ||
79+
!is_writable($MediaRoot)
80+
) {
81+
header($protocol . ' 500 Internal Server Error');
82+
exit();
83+
}
84+
85+
/**
86+
* If we were only supposed to test the server, end here.
87+
*/
88+
if ($testing) {
89+
exit();
90+
}
91+
92+
/**
93+
* If the client did not submit a filesize, exit with HTTP code 400.
94+
*/
95+
if (!isset($_POST['filesize'])) {
96+
header($protocol . ' 400 Bad Request');
97+
exit();
98+
}
99+
100+
/**
101+
* If the client did not upload a file, or something went wrong in the upload
102+
* process, exit with HTTP code 401.
103+
*/
104+
if (
105+
!isset($_FILES['upfile']) ||
106+
$_FILES['upfile']['error'] !== UPLOAD_ERR_OK ||
107+
!is_uploaded_file($_FILES['upfile']['tmp_name'])
108+
) {
109+
header($protocol . ' 401 Unauthorized');
110+
exit();
111+
}
112+
113+
/**
114+
* If the client submitted filesize did not match the uploaded file's size, exit
115+
* with HTTP code 411.
116+
*/
117+
if (intval($_POST['filesize']) !== $_FILES['upfile']['size']) {
118+
header($protocol . ' 411 Length Required');
119+
exit();
120+
}
121+
122+
/**
123+
* Sanitize the file name to maximise server operating system compatibility and
124+
* minimize possible attacks against this implementation.
125+
*/
126+
$filename = preg_replace('@\s+@', '-', $_FILES['upfile']['name']);
127+
$filename = preg_replace('@[^0-9a-z._-]@i', '', $filename);
128+
$target = $MediaRoot . '/' . $filename;
129+
130+
/**
131+
* Move the uploaded file into the target directory. If anything did not work,
132+
* exit with HTTP code 500.
133+
*/
134+
if (!move_uploaded_file($_FILES["upfile"]["tmp_name"], $target)) {
135+
header($protocol . ' 500 Internal Server Error');
136+
exit();
137+
}
138+
139+
exit();

photos/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!DOCTYPE html>

0 commit comments

Comments
 (0)