forked from AllskyTeam/allsky-website
-
Notifications
You must be signed in to change notification settings - Fork 0
/
functions.php
382 lines (342 loc) · 12.7 KB
/
functions.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
<?php
// On Pi's, this placeholder gets replaced with ${ALLSKY_CONFIG}.
// On other machines it won't and references to it will silently fail.
define('ALLSKY_CONFIG', 'XX_ALLSKY_CONFIG_XX');
// Look for $var in the $a array and return its value.
// If not found, return $default.
// If the value is a boolean and is false, an empty string is returned (not a 0).
// A true boolean value returns 1. We want to return 0 if false.
// Ditto for $default.
function v($var, $default, $a) {
if (isset($a[$var])) {
$value = $a[$var];
if (gettype($value) === "boolean" && $value == "")
return(0);
else
return($value);
} else if (gettype($default) === "boolean" && $default == "") {
return(0);
}else {
return($default);
}
}
$configurationFileName = "configuration.json";
// Read the configuration file.
// Some settings impact this page, some impact the constellation overlay.
if (! isset($configFilePrefix))
$configFilePrefix = "";
$configuration_file = $configFilePrefix . $configurationFileName;
if (! file_exists($configuration_file)) {
echo "<p style='color: red; font-size: 200%'>";
echo "ERROR: Missing configuration file '$configuration_file'. Cannot continue.";
echo "</p>";
exit;
}
$settings_str = file_get_contents($configuration_file, true);
$settings_array = json_decode($settings_str, true);
if ($settings_array == null) {
echo "<p style='color: red; font-size: 200%'>";
echo "ERROR: Bad configuration file '<span style='color: black'>$configurationFileName</span>'. Cannot continue.";
echo "<br>Check for missing quotes or commas at the end of every line (except the last one).";
echo "</p>";
echo "<pre>$settings_str</pre>";
exit;
}
$onPi = v("onPi", true, $settings_array['homePage']);
// If on a Pi, check that the placeholder was replaced.
if ($onPi && ALLSKY_CONFIG == "XX_ALLSKY_CONFIG" . "_XX") {
// This file hasn't been updated yet after installation.
echo "<div style='font-size: 200%;'>";
echo "<span style='color: red'>";
echo "If this Website is running on a Pi, please run the following:";
echo "</span>";
echo "<br><code>";
echo " cd ~/allsky";
echo "<br> website/install.sh --update";
echo "</code>";
echo "<span style='color: red'>";
echo "<br><br>If instead, this Website is being run on a remote server, change the <b>onPi</b> variable in the '$configurationFileName' configuration file to <b>false</b>.";
echo "</span>";
echo "</div>";
exit;
}
/*
* Does the exec() function work? It's needed to make thumbnails from video files.
*/
$yes_no = null;
function can_make_video_thumbnails() {
global $yes_no;
if ($yes_no !== null) return($yes_no);
$disabled = explode(',', ini_get('disable_functions'));
// On some servers the disabled array contains leading spaces, so check both ways.
$exec_disabled = in_array('exec', $disabled) || in_array(' exec', $disabled);
if ($exec_disabled) {
echo "<script>console.log('exec() disabled');</script>";
$yes_no = false;
} else {
// See if ffmpeg exists.
@exec("which ffmpeg 2> /dev/null", $ret, $retvalue);
if ($retvalue == 0) {
$yes_no = true;
} else {
echo "<script>console.log('ffmpeg not found');</script>";
$yes_no = false;
}
}
return($yes_no);
}
/*
* Disable buffering.
*/
function disableBuffering() {
ini_set('output_buffering', false);
ini_set('implicit_flush', true);
ob_implicit_flush(true);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_clean();
}
/**
*
* Get a variable from a file and return its value; if not there, return the default.
* NOTE: The variable's value is anything after the equal sign, so there shouldn't be a comment on the line.
* NOTE: There may be something before $searchfor, e.g., "export X=1", where "X" is $searchfor.
*/
function get_variable($file, $searchfor, $default)
{
// get the file contents
if (! file_exists($file)) return($default);
$contents = file_get_contents($file);
if ("$contents" == "") return($default); // file not readable
// escape special characters in the query
$pattern = preg_quote($searchfor, '/');
// finalise the regular expression, matching the whole line
$pattern = "/^.*$pattern.*\$/m";
// search, and store all matching occurences in $matches, but only return the last one
$num_matches = preg_match_all($pattern, $contents, $matches);
if ($num_matches) {
$double_quote = '"';
// Format: [stuff]$searchfor=$value or [stuff]$searchfor="$value"
// Need to delete [stuff]$searchfor= and optional double quotes
$last = $matches[0][$num_matches - 1]; // get the last one
$both = explode( '=', $last);
if (isset($both[1])) {
$last = $both[1]; // everything after equal sign
$last = str_replace($double_quote, "", $last);
} else {
return($default); // nothing after "="
}
return($last);
} else {
return($default);
}
}
$displayed_thumbnail_error_message = false;
function make_thumb($src, $dest, $desired_width)
{
if (! file_exists($src)) {
echo "<br><p class='thumbnailError'>Unable to make thumbnail: '$src' does not exist!</p>";
return(false);
}
if (filesize($src) === 0) {
echo "<br><p class='thumbnailError'>Unable to make thumbnail: '$src' is empty! Removed it.</p>";
unlink($src);
return(false);
}
/* Make sure the imagecreatefromjpeg() function is in PHP. */
global $displayed_thumbnail_error_message;
if ( preg_match("/\.(jpg|jpeg)$/", $src ) ) {
$funcext='jpeg';
} elseif ( preg_match("/\.png$/", $src ) ) {
$funcext='png';
}
if (function_exists("imagecreatefrom${funcext}") == false)
{
if ($displayed_thumbnail_error_message == false)
{
echo "<br><p class='thumbnailError'>Unable to make thumbnail(s); imagecreatefrom{$funcext}() does not exist.<br>If you do NOT have the file '/etc/php/7.3/mods-available/gd.ini' you need to download the latest PHP.</p>";
$displayed_thumbnail_error_message = true;
}
return(false);
}
/* read the source image */
$funcname="imagecreatefrom{$funcext}";
$source_image = $funcname($src);
$width = imagesx($source_image);
$height = imagesy($source_image);
/* find the "desired height" of this thumbnail, relative to the desired width */
if ($desired_width > $width)
$desired_width = $width; // This might create a very tall thumbnail...
$desired_height = floor($height * ($desired_width / $width));
/* create a new, "virtual" image */
$virtual_image = imagecreatetruecolor($desired_width, $desired_height);
/* copy source image at a resized size */
imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
/* create the physical thumbnail image to its destination */
@imagejpeg($virtual_image, $dest);
// flush so user sees thumbnails as they are created, instead of waiting for them all.
flush(); // flush even if we couldn't make the thumbnail so the user sees this file immediately.
if (file_exists($dest)) {
if (filesize($dest) === 0) {
echo "<br><p class='thumbnailError'>Unable to make thumbnail for '$src': thumbnail was empty! Using full-size image for thumbnail.</p>";
unlink($dest);
return(false);
}
return(true);
} else {
echo "<p class='thumbnailError'>Unable to create thumbnail for '$src': <b>" . error_get_last()['message'] . "</b></p>";
return(false);
}
}
// Did creation of last thumbnail work?
// If not, don't try to create any more since they likely won't work either.
$last_thumbnail_worked = true;
// Similar to make_thumb() but using a video for the input file.
function make_thumb_from_video($src, $dest, $desired_width, $attempts)
{
global $last_thumbnail_worked;
if (! $last_thumbnail_worked) {
return(false);
}
if (! can_make_video_thumbnails()) {
return(false);
}
if (! file_exists($src)) {
echo "<br><p class='thumbnailError'>Unable to make thumbnail: '$src' does not exist!</p>";
return(false);
}
if (filesize($src) === 0) {
echo "<br><p class='thumbnailError'>Unable to make thumbnail: '$src' is empty! Removed it.</p>";
unlink($src);
return(false);
}
// Start 5 seconds in to skip any auto-exposure changes at the beginning.
// This of course assumes the video is at least 5 sec long. If it's not, we won't be able
// to create a thumbnail, so call ourselfs a second time using 1 second.
// If the file is less than 1 second long, well, too bad.
// "-1" scales the height to the original aspect ratio.
if ($attempts === 1)
$sec = "05";
else
$sec = "00";
$command = "ffmpeg -loglevel warning -ss 00:00:$sec -i '$src' -filter:v scale='$desired_width:-1' -frames:v 1 '$dest' 2>&1";
$output = array();
exec($command, $output);
if (file_exists($dest)) {
if (filesize($dest) === 0) {
echo "<br><p class='thumbnailError'>Unable to make thumbnail for '$src': thumbnail was empty! Using full-size image for thumbnail.</p>";
unlink($dest);
return(false);
}
return(true);
}
//echo "<br>Attempt $attempts: Failed to make thumbnail for $src using $sec seconds:<br>$command";
if ($attempts >= 2) {
echo "<br>Failed to make thumbnail for $src after $attempts attempts.<br>";
echo "Last command: $command";
echo "<br>Output from command: <b>" . $output[0] . "</b>";
$last_thumbnail_worked = false;
return(false);
}
return make_thumb_from_video($src, $dest, $desired_width, $attempts+1);
}
// Display thumbnails with links to the full-size files
// for startrails, keograms, and videos.
// The function to make thumbnails for videos is different
$back_button = "<a class='back-button' href='../index.php'><i class='fa fa-chevron-left'></i> Back to Live View</a>";
function display_thumbnails($dir, $file_prefix, $title)
{
global $back_button;
if ($file_prefix === "allsky") {
$ext = "/\.(mp4|webm)$/";
} else {
$ext = "/\.(jpg|jpeg|png)$/";
}
$file_prefix_len = strlen($file_prefix);
$num_files = 0;
$files = array();
if ($handle = opendir($dir)) {
while (false !== ($entry = readdir($handle))) {
if ( preg_match( $ext, $entry ) ) {
$files[] = $entry;
$num_files++;
}
}
closedir($handle);
}
if ($num_files == 0) {
echo "<p>$back_button</p>";
echo "<div class='noImages'>No $title</div>";
return;
}
asort($files);
$thumb_dir = "$dir/thumbnails";
if (! is_dir($thumb_dir)) {
if (! mkdir($thumb_dir, 0775))
echo "<p>Unable to make '$thumb_dir' directory. You will need to create it manually.</p>";
print_r(error_get_last());
}
echo "<table class='imagesHeader'><tr><td class='headerButton'>$back_button</td> <td class='headerTitle'>$title</td></tr></table>";
echo "<div class='archived-files'>\n";
$thumbnailSizeX = get_variable(ALLSKY_CONFIG .'/config.sh', 'THUMBNAIL_SIZE_X=', '100');
foreach ($files as $file) {
// The thumbnail should be a .jpg.
$thumbnail = preg_replace($ext, ".jpg", "$dir/thumbnails/$file");
if (! file_exists($thumbnail)) {
if ($file_prefix == "allsky") {
if (! make_thumb_from_video("$dir/$file", $thumbnail, $thumbnailSizeX, 1)) {
// We can't use the video file as a thumbnail
$thumbnail = "../NoThumbnail.png";
}
} else {
if (! make_thumb("$dir/$file", $thumbnail, $thumbnailSizeX)) {
// Using the full-sized file as a thumbnail is overkill,
// but it's better than no thumbnail.
$thumbnail = "$dir/$file";
}
}
// flush so user sees thumbnails as they are created, instead of waiting for them all.
//echo "<br>flushing after $file:";
flush();
}
$year = substr($file, $file_prefix_len + 1, 4);
$month = substr($file, $file_prefix_len + 5, 2);
$day = substr($file, $file_prefix_len + 7, 2);
$date = $year.$month.$day;
echo "<a href='$dir/$file'><div class='day-container'><div class='img-text'><div class='image-container'><img id=".$date." src='$thumbnail' title='$file_prefix-$year-$month-$day'/></div><div class='day-text'>$year-$month-$day</div></div></div></a>\n";
}
echo "</div>"; // archived-files
echo "<div class='archived-files-end'></div>"; // clears "float" from archived-files
echo "<div class='archived-files'><hr></div>";
}
// Read and decode a json file, returning the decoded results or null.
// On error, display the specified error message
function get_decoded_json_file($file, $associative, $errorMsg) {
if (! file_exists($file)) {
echo "<div style='color: red; font-size: 200%;'>";
echo "$errorMsg:";
echo "<br>File '$file' missing!";
echo "</div>";
return null;
}
$str = file_get_contents($file, true);
if ($str === "") {
echo "<div style='color: red; font-size: 200%;'>";
echo "$errorMsg:";
echo "<br>File '$file' is empty!";
echo "</div>";
return null;
}
$str_array = json_decode($str, $associative);
if ($str_array == null) {
echo "<div style='color: red; font-size: 200%;'>";
echo "$errorMsg:";
echo "<br>" . json_last_error_msg();
$cmd = "json_pp < $file 2>&1";
exec($cmd, $output);
echo "<br>" . implode("<br>", $output);
echo "</div>";
return null;
}
return $str_array;
}
?>