po/src/install.php

1194 lines
43 KiB
PHP

<?php
// Copyright (C) 2002-2006 Balint Kis (balint@k-i-s.net)
// Copyright (C) 2005-2019 Solomon Peachy (pizza@shaftnet.org)
// This program 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, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/* =============================================================== */
/*
The mappings can be one of two types:
"src_ver" => array("file" => db_file_name)
db_file_name is a sql dumpfile.
"src_ver" => array("function" => function_name)
function function_name($database) { ... return BOOL;}
*/
$versions = array("(none)" => array("function" => "po_new_install"),
"2.29.B" => array("file" => "po.upgrade.2.29.b.to.2.30.b.sql"),
"2.30.B" => array("file" => "po.upgrade.2.30.b.to.2.31.a.sql"),
"2.31.A" => array("file" => "po.upgrade.2.31.a.to.2.32.a.sql"),
"2.32.A" => array("file" => "po.upgrade.2.32.a.to.2.33.x.sql"),
"2.32.X" => array("function" => "po_upgrade_233x_233y"),
"2.32.Y" => array("file" => "po.upgrade.2.32.y.to.2.33.a.sql"),
"2.33.A" => array("function" => "po_upgrade_233a_234a"),
"2.34.A" => array("file" => "po.upgrade.2.34.a.to.2.34.b.sql"),
"2.34.B" => array("function" => "po_upgrade_234b_234c"),
"2.34.C" => array("file" => "po.upgrade.2.34.c.to.2.34.d.sql"),
"2.34.E" => array("file" => "po.upgrade.2.34.d.to.2.35.a.sql"), // For people that applied a hotfix to 2.34
"2.34.D" => array("file" => "po.upgrade.2.34.d.to.2.35.a.sql"),
"2.35.A" => array("file" => "po.upgrade.2.35.a.to.2.35.b.sql"),
"2.35.B" => array("file" => "po.upgrade.2.35.b.to.2.36.a.sql"),
"2.36.A" => array("function" => "po_upgrade_236a_236b"),
"2.36.B" => array("file" => "po.upgrade.2.36.b.to.2.36.c.sql"),
"2.36.C" => array("file" => "po.upgrade.2.36.c.to.2.36.d.sql"),
"2.36.D" => array("file" => "po.upgrade.2.36.d.to.2.37.a.sql"),
"2.37.A" => array("file" => "po.upgrade.2.37.a.to.2.37.b.sql"),
"2.37.B" => array("file" => "po.upgrade.2.37.b.to.2.37.c.sql"),
"2.37.C" => array("file" => "po.upgrade.2.37.c.to.2.38.a.sql"),
"2.38.A" => array("file" => "po.upgrade.2.38.a.to.2.38.b.sql"),
"2.38.B" => array("function" => "po_upgrade_238b_238c"),
);
// to prepare a dump, perform a new install + upgrade, and then do this:
// pg_dump --disable-dollar-quoting -D -O -s -U po_user po_db > /tmp/dumpfile
// perl -pni -e "s/\'2013.*?\'/now()/g;" /tmp/dumpfile
// you'll need to remove the 'add langage' and 'set schema' stuff too.
/* ===================== Helper Functions ====================== */
function po_symlink($src, $dest) {
chdir(dirname($src));
$src = escapeshellarg(basename($src));
$dest = escapeshellarg($dest);
$retval;
system("ln -s $src $dest", $retval);
return ($retval == 0);
}
function po_process_db_file($database, $file) {
$fh = fopen($file, 'r');
if (!$fh) {
print (" can't open file $row[db_file] \n");
return FALSE;
}
$quot = 0;
# $buffer = "-- ";
$buffer = "";
while (!feof($fh)) {
$line = fgets($fh, 4096);
# print ("READ:<pre>$line</pre><br/>\n");
$offset = strpos($line, '--');
if ($offset !== FALSE) {
$line = substr($line, 0, $offset);
}
$line = trim($line);
$buffer .= "\n$line";
/* If the last character on a line is a singlequote, then treat all
that follows as a single line -- until thenext line that ends with
a singlequote. */
if (substr($line, -1) == "'") {
# print ("<pre>-- $quot --$line</pre><br/>\n");
$quot = !$quot;
if (substr(ltrim($line), 0, 4) == "AS '") {
$quot = !$quot;
}
}
# print ("READ2: <pre>quot $quot offset $offset len " . strlen($line) ."</pre><br/><pre>$buffer</pre><br/>");
/* If we don't get a semicolon at the end of the line, keep reading
until we do, and execute the whole thing in one query.*/
$offset = strrpos($buffer, ";");
if (!$quot && ($offset === (strlen($buffer)-1))) {
$buffer = substr($buffer, 0, $offset);
# print ("<pre>$buffer</pre><br/>\n");
$res = pg_query($database, $buffer);
if ($res === FALSE) {
print ("<pre>-- $quot -- FAILED: $buffer</pre><pre>$res</pre><br/>\n");
return FALSE;
}
$buffer = "";
# $buffer = "-- ";
}
}
fclose($fh);
if ($quot == 1) {
print "<pre>Quoting problem...</pre>";
return FALSE;
}
return TRUE;
}
function po_get_version($database) {
$query = pg_query($database, "select major, minor, variation from version");
if ($query != FALSE) {
$row = pg_fetch_row($query);
$version = sprintf("%d.%02d.%s", $row[0],$row[1],$row[2]);
} else {
$version = "(none)";
}
return $version;
}
/* ==================== Migration Functions ===================== */
/* iptc and exif stuff storage updated */
function po232_iptc_exif($database) {
$trans = array("<tr><td>" => "<key>",
"</td><td>" => "</key><value>",
"</td></tr>\n" => "</value>");
print "<li>Translating EXIF/IPTC data to new format...";
$data = pg_query($database, "select identifier, exif, iptc from photo_tech where exif != '' or iptc != ''");
for ($i=0; $i < pg_num_rows($data); $i++) {
$dat = pg_fetch_assoc($data, $i);
$exif = strtr($dat['exif'], $trans);
$iptc = strtr($dat['iptc'], $trans);
if (($exif == $dat['exif']) &&
($iptc == $dat['iptc']))
continue;
$exif = pg_escape_string($database, $exif);
$iptc = pg_escape_string($database, $iptc);
$res = pg_query($database, "update photo_tech set exif = '$exif', iptc = '$iptc' where identifier = $dat[identifier]");
print " $dat[identifier] ";
if (!$res) {
print "<font color=\"red\">FAILED (# $dat[identifier])</font></li>\n";
return FALSE;
}
}
print "<font color=\"green\">OK</font></li>\n";
return TRUE;
}
/* Migrate to new keyword table layout */
function semi_string_to_array($str){
$expr="/;(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/";
$results=preg_split($expr,trim($str));
return preg_replace("/^\"(.*)\"$/","$1",$results);
}
function space_string_to_array($str){
$expr="/ (?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/";
$results=preg_split($expr,trim($str));
return preg_replace("/^\"(.*)\"$/","$1",$results);
}
function po232_keyword_migrate($database) {
print "<li>Moving keyword data into a separate table...";
$data = pg_query($database, "select identifier, keyword from photo where keyword != ''");
for ($i=0; $i < pg_num_rows($data); $i++) {
$dat = pg_fetch_assoc($data, $i);
$photo = $dat['identifier'];
if (strstr($dat['keyword'], ";"))
$keywords = semi_string_to_array($dat['keyword']);
else
$keywords = space_string_to_array($dat['keyword']);
foreach ($keywords as $keyword) {
$keyword = strtolower(trim($keyword));
$keyword = trim($keyword, ','); /* Trailing commas */
$keyword = trim($keyword);
if ($keyword == "") continue;
$keyword = pg_escape_string($database, $keyword);
$res = pg_query($database, "insert into photo_keywords (photo, keyword) values ($photo, '$keyword')");
if (!$res) {
print "<font color=\"red\">FAILED</font></li>\n";
return FALSE;
}
}
}
print "<font color=\"green\">OK</font></li>\n";
return TRUE;
}
function po_upgrade_233x_233y($database) {
$res = pg_query($database, "begin");
$res = po232_keyword_migrate($database);
if ($res)
$res = po232_iptc_exif($database);
if ($res)
$res = pg_query($database, "update version set minor=33, variation='Y'");
if ($res) {
pg_query($database, "commit");
} else {
print "<li><pre>".pg_last_error($database)."</pre></li>";
pg_query($database, "rollback");
}
return $res;
}
function po_upgrade_233a_234a($database) {
global $po_options_default;
global $image_repository_path;
$res = TRUE;
/* Migrate the 'current volume' pref into the filesystem directly */
if (!readlink($image_repository_path."/current")) {
$system_preferences = pg_fetch_row(pg_query($database, "select current_volume from system_preferences"));
$new_volume = $system_preferences[0];
$res = po_symlink($new_volume, "$image_repository_path/current");
}
if (!$res)
return $res;
/* ... detect and clean up bogus images ... */
print "<li>Checking for bogus files...</li>";
$bogus = array();
$files = array();
$versions = pg_query($database, "SELECT identifier, small_image_path, medium_image_path, large_image_path, photo FROM photo_version order by identifier");
for ($i = 0 ; $i < pg_num_rows($versions) ; $i++) {
$row = pg_fetch_row($versions, $i);
/* Check original file type */
$file_type = strtolower(substr($row[3], strrpos($row[3], ".") + 1));
if (
// ($file_type == "xmp") ||
!is_readable("$image_repository_path/$row[1]") ||
!is_readable("$image_repository_path/$row[2]") ||
!is_readable("$image_repository_path/$row[3]")) {
$bogus[] = $row[4];
$files[] = "$image_repository_path/$row[1]";
$files[] = "$image_repository_path/$row[2]";
$files[] = "$image_repository_path/$row[3]";
}
}
/* If we find some bogus images ... */
if (count($bogus) > 0) {
$list = implode(", ", $bogus);
print "<li>";
print "<ul><li>Deleting bogus images ( $list )...</li>";
$res = pg_query($database, "begin");
/* ... nuke them from the database ... */
$queries = array("delete from photo_keywords where photo in ($list)",
"delete from photo_spooler where photo in ($list)",
"delete from album_content where photo in ($list)",
"delete from submission where photo_dupe in (select photo_dupe.identifier from photo_dupe where photo_dupe.photo in ($list))",
"delete from photo_dupe where photo in ($list)",
"delete from photo_version where photo in ($list)",
"delete from photo_tech where photo in ($list)",
"delete from rating where photo in ($list)",
"delete from photo where identifier in ($list)");
foreach ($queries as $query) {
$res = pg_query($database, $query);
if (!$res) {
print "<li><pre>$query</pre></li>";
break;
}
}
/* ... then delete the files ... */
if ($res) {
$err = error_reporting(0);
foreach ($files as $file) {
print "<li><pre>$file</pre></li>";
unlink("$file");
}
error_reporting($err);
pg_query($database, "commit");
print "<li>...done.</li>";
} else {
print "<li><pre>".pg_last_error($database)."</pre></li>";
pg_query($database, "rollback");
print "<li><font color=\"red\">...FAILED!</font></li>";
}
print "</ul></li>";
}
if (!$res)
return $res;
/* Update the DB revision */
$res = pg_query($database, "update version set minor=34, variation='A'");
return $res;
}
function po_upgrade_234b_234c($database) {
$res = po234_migrateprefs($database);
if ($res)
$res = po234_migrate_photo_files($database);
return $res;
}
function po234_migrateprefs($database) {
global $po_options_default;
$user_list = array();
print("<li><ul>");
$res = pg_query($database, "begin");
$users = pg_query($database, "select identifier from users where not exists(select owner from user_preferences where owner = users.identifier) order by identifier");
while (($user = pg_fetch_row($users)) != FALSE) {
$user_list[] = $user[0];
}
/* If there's no work to do, skip it. */
if (!sizeof($user_list)) {
return TRUE;
}
foreach ($user_list as $user) {
$po_user = array("id" => $user);
$options = array();
$user_data = pg_fetch_row(pg_query($database, "select username, password, first_name, last_name, company, contact, preferences, imagemagick_options, imagemagick_composite_options, dcraw_options, type from users where identifier='$po_user[id]'"));
print("<li>Migrating '$user_data[0]' (# $po_user[id])</li>");
$po_user['prefs_id'] = $user_data[6];
$po_user['im_id'] = $user_data[7];
$po_user['im_composite_id'] = $user_data[8];
$po_user['dcraw_id'] = $user_data[9];
/* Basic preferences */
$preferences = pg_fetch_row(pg_query($database, "
select print_out, start_hour, end_hour, start_day,
folder_view, paper, label, popup_enable, popup_delay, search_enable_stemming,
search_default_mode, download_counter, download_expiry_period, shop_enable,
bulk_upload_enable, quota_size, quota_count
from preferences
where identifier=$po_user[prefs_id]"));
$options['print_out'] = $preferences[0];
$options['start_hour'] = $preferences[1];
$options['end_hour'] = $preferences[2];
$options['start_day'] = $preferences[3];
$options['photo_view'] = $preferences[4];
$options['paper'] = $preferences[5];
$options['label'] = $preferences[6];
$options['popup_enable'] = $preferences[7];
$options['popup_delay'] = $preferences[8];
$options['search_enable_stemming'] = $preferences[9];
$options['search_engine_type'] = $preferences[10];
$options['bulk_upload_enable'] = $preferences[14];
$options['quota_size'] = $preferences[15];
$options['quota_count'] = $preferences[16];
/* Raw imports */
$dcraw_options = pg_fetch_row(pg_query($database, "
select gamma, brightness, white_balance, bitdepth
from dcraw_options
where dcraw_options.identifier = $po_user[dcraw_id]"));
$options['dcraw_gamma'] = $dcraw_options[0];
$options['dcraw_brightness'] = $dcraw_options[1];
$options['dcraw_white_balance'] = $dcraw_options[2];
$options['dcraw_bitdepth'] = $dcraw_options[3];
/* Watermarking */
$imagemagick_composite_options = pg_fetch_row(pg_query($database, "
select gravity, watermark, (select photo from photo_version where identifier = imagemagick_composite_options.photo_version)
from imagemagick_composite_options
where imagemagick_composite_options.identifier=$po_user[im_composite_id]"));
$options['watermark_location'] = $imagemagick_composite_options[0];
$options['watermark_brightness'] = $imagemagick_composite_options[1];
$options['watermark_photo'] = $imagemagick_composite_options[2];
/* Preview & Thumbnail stuffs */
$imagemagick_options = pg_fetch_row(pg_query($database, "
select preview_quality, preview_colorspace, preview_gamma,
preview_sharpen_radius, preview_sharpen_sigma,
preview_sharpen_amount, preview_sharpen_threshold,
preview_border_width, preview_border_height, preview_border_color,
thumb_quality, thumb_colorspace, thumb_gamma,
thumb_sharpen_radius, thumb_sharpen_sigma,
thumb_sharpen_amount, thumb_sharpen_threshold,
thumb_border_width, thumb_border_height, thumb_border_color
from imagemagick_options
where identifier=$po_user[im_id]"));
$options['preview_quality'] = $imagemagick_options[0];
$options['preview_color_space'] = $imagemagick_options[1];
$options['preview_gamma'] = $imagemagick_options[2];
$options['preview_sharpen_radius'] = $imagemagick_options[3];
$options['preview_sharpen_sigma'] = $imagemagick_options[4];
$options['preview_sharpen_amount'] = $imagemagick_options[5];
$options['preview_sharpen_threshold'] = $imagemagick_options[6];
$options['preview_border_width'] = $imagemagick_options[7];
$options['preview_border_height'] = $imagemagick_options[8];
$options['preview_border_color'] = $imagemagick_options[9];
$options['thumb_quality'] = $imagemagick_options[10];
$options['thumb_color_space'] = $imagemagick_options[11];
$options['thumb_gamma'] = $imagemagick_options[12];
$options['thumb_sharpen_radius'] = $imagemagick_options[13];
$options['thumb_sharpen_sigma'] = $imagemagick_options[14];
$options['thumb_sharpen_amount'] = $imagemagick_options[15];
$options['thumb_sharpen_threshold'] = $imagemagick_options[16];
$options['thumb_border_width'] = $imagemagick_options[17];
$options['thumb_border_height'] = $imagemagick_options[18];
$options['thumb_border_color'] = $imagemagick_options[19];
/* Now dump the preference crap into the new table */
foreach ($options as $key => $value) {
$key = pg_escape_string($database, $key);
$value = pg_escape_string($database, $value);
if ($value == "") continue;
if ($po_options_default[$key] == $value) continue; // Only migrate if they're not default!
$res = pg_query($database, "INSERT INTO user_preferences(owner, key, value) VALUES ($po_user[id], '$key', '$value')");
if (!$res) {
print("<pre>Can't migrate prefs: $owner, $key, $value</pre>");
break;
}
}
}
print "<li>All users migrated</li>";
if (!$res) {
print "<li><pre>!!!" . pg_last_error($database) . "</pre></li>\n";
pg_query($database, "rollback");
} else {
pg_query($database, "commit");
}
print("</ul></li>");
return $res;
}
function po_get_image_size($file) {
global $sys_exiftool;
$width = 0;
$height = 0;
$handle = popen("$sys_exiftool -ImageWidth -ImageHeight $file", "r");
if ($handle) {
while (!feof($handle)) {
$line = fgets($handle);
$parts = explode(":", $line, 2);
$parts[0] = trim($parts[0]);
if (!isset($parts[1])) continue;
$parts[1] = trim($parts[1]);
if ($parts[0] == "Image Width") $width = $parts[1];
if ($parts[0] == "Image Height") $height = $parts[1];
//print "<!-- XXX $parts[0] : $parts[1] -- $width $height -->\n";
}
pclose($handle);
}
if (!$width || !$height) {
print "<li><font color=\"red\">File $file not recognisable as an image!</font></li>";
}
return array($width,$height);
}
function po234_migrate_photo_files($database) {
global $image_repository_path;
$res = TRUE;
print("<li><ul>");
print "<li>Migrating photo file table....</li>";
$versions = pg_query($database, "SELECT identifier, small_image_path, medium_image_path, large_image_path, date_changed, photo FROM photo_version WHERE identifier not in (select distinct version from files) order by identifier");
for ($i = 0 ; $i < pg_num_rows($versions) ; $i++) {
$row = pg_fetch_row($versions, $i);
print "<li>Migrating photo $row[5] version $row[0]</li>";
$res = pg_query($database, "begin");
/* Small image */
$image_dimension = po_get_image_size($image_repository_path."/".$row[1]);
$size = filesize($image_repository_path."/".$row[1]);
$query = "INSERT INTO files (identifier, version, size, x_res, y_res, path, created, filesize, params, comments, watermark) VALUES ((select nextval('files_id_sequence')), $row[0], 1, $image_dimension[0], $image_dimension[1], '$row[1]', '$row[4]', $size, '', '', null)";
$res = pg_query($database, $query);
/* Preview image */
if ($res) {
$image_dimension = po_get_image_size($image_repository_path."/".$row[2]);
$size = filesize($image_repository_path."/".$row[2]);
$query = "INSERT INTO files (identifier, version, size, x_res, y_res, path, created, filesize, params, comments, watermark) VALUES ((select nextval('files_id_sequence')), $row[0], 2, $image_dimension[0], $image_dimension[1], '$row[2]', '$row[4]', $size, '', '', null)";
$res = pg_query($database, $query);
}
/* Original image */
if ($res) {
$image_dimension = po_get_image_size($image_repository_path."/".$row[3]);
$size = filesize($image_repository_path."/".$row[3]);
$query = "INSERT INTO files (identifier, version, size, x_res, y_res, path, created, filesize, params, comments, watermark) VALUES ((select nextval('files_id_sequence')), $row[0], 3, $image_dimension[0], $image_dimension[1], '$row[3]', '$row[4]', $size, '', '', null)";
$res = pg_query($database, $query);
}
if ($res) {
$res = pg_query($database, "commit");
} else {
print "<li><pre>$query</pre></li>";
pg_query($database, "abort");
break;
}
flush();
}
if ($res || $i == 0) {
/* Ensure we have something left */
$res = pg_query($database, "begin");
$res = pg_fetch_row(pg_query($database, "SELECT count(*) from photo_version where identifier not in (select distinct version from files)"));
if ($res) {
$res = pg_query($database, "commit");
$res = TRUE;
} else {
pg_query($database, "abort");
$res = FALSE;
}
}
if ($res) {
$res = pg_query($database, "update version set minor=34, variation='C'");
}
print "</ul></li>";
return $res;
}
/* Migrate the equipment tables */
function po_upgrade_236a_236b($database) {
$types = array('filter' => 1, 'flash' => 2, 'scanner' => 3, 'support' => 4);
print "<ul>";
foreach ($types as $type_n => $type_id) {
print "<li>Migrating $type_n<ul>";
$sku_maps = array(); // maps old id ==> new id
/* First create new equipment sku entry */
$skus = pg_query($database, "select identifier, manufacturer, model, variation from ".$type_n."_type");
if (!$skus) continue;
$res = TRUE;
pg_query($database, "begin");
for ($i = 0 ; $i < pg_num_rows($skus) ; $i++) {
$sku = pg_fetch_row($skus);
$sku_id = pg_fetch_row(pg_query($database, "select nextval('equipment_sku_id_seq')"));
$sku_id = $sku_id[0];
$sku_model = pg_escape_string($database, "$sku[2] $sku[3]");
print "<li>Migrating $sku[0] - $sku[2] $sku[3] -> $sku_id</li>";
$res = pg_query($database, "insert into equipment_sku (identifier, type, manufacturer, model, properties, url) VALUES ($sku_id, $type_id, $sku[1], '$sku_model', null, null)");
if (!$res) break;
$sku_maps[$sku[0]] = $sku_id;
}
if ($res) {
$equip_maps = array(); // maps old id ==> new id
/* Migrate the equipment instances */
$equips = pg_query($database, "select identifier, type, users, date_of_purchase, purchased_new, access_rights, serial_number from $type_n");
for ($i = 0 ; $i < pg_num_rows($equips) ; $i++) {
$equip = pg_fetch_row($equips);
$equip_id = pg_fetch_row(pg_query($database, "select nextval('equipment_id_seq')"));
$equip_id = $equip_id[0];
if ($equip[3] == '') {
$equip[3] = 'null';
} else {
$equip[3] = "'$equip[3]'";
}
$res = pg_query($database, "insert into equipment (identifier, sku, users, purchase_date, purchased_new, access_rights, properties, serial) VALUES ($equip_id, ".$sku_maps[$equip[1]].", $equip[2], $equip[3], '$equip[4]', $equip[5], '', '$equip[6]')");
if (!$res) break;
$equip_maps[$equip[0]] = $equip_id;
}
}
if ($res) {
/* Convert all references to equipment */
foreach ($equip_maps as $key => $value) {
$res = pg_query($database, "insert into photo_equipment (photo, equipment, type) SELECT photo, $value, $type_id from photo_tech where $type_n = $key");
if (!$res) break;
}
}
if ($res) {
pg_query($database, "commit");
} else {
pg_query($database, "abort");
print "<font color=\"red\"> FAILED </font>\n";
print "<pre>" . pg_last_error($database) . "</pre>\n";
break;
}
print "</ul></li>";
}
# Lenses. More complicated.
if ($res) {
$type_n = 'lens';
$type_id = 5;
print "<li>Migrating $type_n<ul>";
$sku_maps = array(); // maps old id ==> new id
/* First create new equipment sku entry */
$skus = pg_query($database, "select identifier, manufacturer, model, variation, min_focal_length, max_focal_length, min_aperture, max_aperture, exiftool_lens_id from lens_type");
$res = TRUE;
pg_query($database, "begin");
for ($i = 0 ; $i < pg_num_rows($skus) ; $i++) {
$sku = pg_fetch_row($skus);
$sku_id = pg_fetch_row(pg_query($database, "select nextval('equipment_sku_id_seq')"));
$sku_id = $sku_id[0];
if ($sku[8]) { /* Use ExifTool ID if possible */
$sku_model = $sku[8];
} else {
$flength = $sku[4];
if ($sku[4] != $sku[5])
$flength .= "-$sku[5]";
$flength .= "mm";
$ap = $sku[6];
if ($sku[6] != $sku[7])
$ap .= "-$sku[7]";
$ap = "f/$ap";
$sku_model = "$sku[2] $sku[3] $flength $ap";
}
print "<li>Migrating $sku[0] - $sku_model -> $sku_id</li>";
$sku_model = pg_escape_string($database, $sku_model);
$res = pg_query($database, "insert into equipment_sku (identifier, type, manufacturer, model, properties, url) VALUES ($sku_id, $type_id, $sku[1], '$sku_model', null, null)");
if (!$res) break;
$sku_maps[$sku[0]] = $sku_id;
}
if ($res) {
$equip_maps = array(); // maps old id ==> new id
/* Migrate the equipment instances */
$equips = pg_query($database, "select identifier, type, users, date_of_purchase, purchased_new, access_rights, serial_number from $type_n");
for ($i = 0 ; $i < pg_num_rows($equips) ; $i++) {
$equip = pg_fetch_row($equips);
$equip_id = pg_fetch_row(pg_query($database, "select nextval('equipment_id_seq')"));
$equip_id = $equip_id[0];
if ($equip[3] == '') {
$equip[3] = 'null';
} else {
$equip[3] = "'$equip[3]'";
}
$res = pg_query($database, "insert into equipment (identifier, sku, users, purchase_date, purchased_new, access_rights, properties, serial) VALUES ($equip_id, ".$sku_maps[$equip[1]].", $equip[2], $equip[3], '$equip[4]', $equip[5], '', '$equip[6]')");
if (!$res) break;
$equip_maps[$equip[0]] = $equip_id;
}
}
if ($res) {
/* Convert all references to equipment */
foreach ($equip_maps as $key => $value) {
$res = pg_query($database, "insert into photo_equipment (photo, equipment, type) SELECT photo, $value, $type_id from photo_tech where $type_n = $key");
if (!$res) break;
}
}
if ($res) {
pg_query($database, "commit");
} else {
pg_query($database, "abort");
print "<font color=\"red\"> FAILED </font>\n";
print "<pre>" . pg_last_error($database) . "</pre>\n";
}
print "</ul></li>";
}
if ($res) {
$res = pg_query($database, "update version set minor=36, variation='B'");
}
print "</ul>";
return $res;
}
function po_get_image_iso($file) {
global $sys_exiftool;
$iso = FALSE;
$handle = popen("$sys_exiftool -Iso -AutoISO '$file'", "r");
if ($handle) {
while (!feof($handle)) {
$line = fgets($handle);
$parts = explode(":", $line, 2);
$parts[0] = trim($parts[0]);
if (!isset($parts[1])) continue;
if (!is_numeric($parts[1])) continue;
$parts[1] = trim($parts[1]);
if ($parts[0] == "ISO") $iso = $parts[1];
if ($parts[0] == "Auto ISO" && $iso === FALSE) $iso = $parts[1];
}
pclose($handle);
}
return $iso;
}
function po_upgrade_238b_238c($database) {
global $image_repository_path;
print "<li><ul>\n";
/* Query list of images that are lacking ISO entries */
$images = pg_query($database, "SELECT v.photo, f.path
FROM files f, photo_tech t, photo_version v
WHERE v.key = 1
AND f.size = 0
AND t.iso_override IS NULL
AND t.film IS NULL
AND t.aperture IS NOT NULL
AND t.photo = v.photo
AND f.version = v.identifier
ORDER BY f.version");
print "<li>Fixing up images that lack ISO database entries...(".pg_num_rows($images).")</li>";
$res = pg_query($database, "begin");
/* Iterate through them, and fix them up one by one */
for ($i = 0; $i < pg_num_rows($images) ; $i++) {
$dat = pg_fetch_assoc($images, $i);
$iso = po_get_image_iso($image_repository_path."/".$dat['path']);
if ($iso === FALSE) {
print "<li>skipping $dat[photo]</li>\n";
continue;
}
$row = "UPDATE photo_tech SET iso_override = '$iso' WHERE photo = '$dat[photo]'";
print "<li>$row</li>\n";
$res = pg_query($row);
if ($res === FALSE)
break;
/* Flush every 25 rows in case we get terminated */
if ($i && ($i % 25 == 0)) {
flush();
$res = pg_query($database, "commit");
$res = pg_query($database, "begin");
}
}
if ($res)
$res = pg_query($database, "update version set minor=38, variation='C'");
if ($res) {
$res = pg_query($database, "commit");
print "<li><font color=\"green\">OK</font></li>\n";
} else {
print "<li><font color=\"red\">FAILED</font></li>\n";
print "<li><pre>".pg_last_error($database)."</pre></li>";
pg_query($database, "rollback");
}
print "</ul></li>";
// exit(0);
return $res;
}
function po_new_install($database) {
global $image_repository_path;
global $first_volume;
global $new_install;
global $db_dsn;
$new_install = TRUE;
/* Ensure we have pl/pgsql support */
$res = pg_query("select * from pg_language where lanname = 'plpgsql'");
print "<li>Checking for PL/PGSQL support...";
if (pg_num_rows($res) > 0) {
print "<font color=\"green\">OK</font></li>\n";
} else {
$list = split(" ", $db_dsn);
$db_name = "put_po_db_name_here";
foreach ($list as $item) {
$pair = split("=", $item);
if ($pair[0] == 'dbname') {
$db_name = $pair[1];
}
}
print "<font color=\"red\">FAILED</font></li>\n";
print "<li>Run this command as root:<br/>\n";
print "<pre>su - postgres -c \"createlang plpgsql $db_name\"</pre></li>\n";
return FALSE;
}
/* Set up the repository on disk */
print "<li>Creating initial image repository layout...";
if (file_exists("$image_repository_path/$first_volume")) {
print "<font color=\"red\">FAILED</font> (incomplete repository already exists under $image_repository_path)</li>\n";
return FALSE;
}
$res = mkdir("$image_repository_path/$first_volume/00000", 0700, TRUE);
if ($res)
$res = mkdir("$image_repository_path/$first_volume/00001", 0700, TRUE);
if ($res)
$res = po_symlink($first_volume, "$image_repository_path/current");
if ($res) {
print "<font color=\"green\">OK</font></li>\n";
} else {
print "<font color=\"red\">FAILED</font> <pre>$image_repository_path/$first_volume</pre></li>\n";
}
/* Load up SQL data */
if ($res) {
print "<li>Loading initial database data...";
pg_query($database, "begin");
$res = po_process_db_file($database, "sql/po.initial.2.35.a.sql");
if ($res) {
pg_query($database, "commit");
print "<font color=\"green\">OK</font></li>\n";
} else {
pg_query($database, "rollback");
print "<font color=\"red\">FAILED</font></li>\n";
print "<li><pre>" . pg_last_error($database) . "</pre></li>\n";
}
}
return $res;
}
/* =============================================================== */
function display_db_form() {
global $db_dsn;
global $image_repository_path;
global $site_url;
global $site_title;
global $strings;
$db_dsn = preg_replace("/password=(.*)/", "password=[hidden]", $db_dsn);
print "<h4>Configured Settings: If any of these are incorrect, edit include/config_site.php</h4>\n";
print "<form method=\"post\" action=\"install.php\" accept-charset=\"".$strings['formats_encoding']."\">\n";
print "<table class=\"listing\">\n";
print "<tr><td>Database Connection<br/>String</td><td>$db_dsn</td></tr>\n";
print "<tr><td>Site URL</td><td>$site_url</td></tr>\n";
print "<tr><td>Site Title</td><td>$site_title</td></tr>\n";
print "<tr><td>Image Repository</td><td>$image_repository_path</td></tr>\n";
print "</table>\n";
print "<input type=\"hidden\" name=\"go\" value=\"1\" />\n";
print make_button("submit_button", "submit", "Install/Upgrade");
print "</form>\n";
}
/* =============================================================== */
$db_dsn = "host=localhost port=5432 dbname=po_db user=po_user password=password";
$image_repository_path = "/export/po_dev_image_repository";
$site_url = "http://localhost/po";
$site_title = "My Photo Organizer";
$theme = "themes/aqua"; // XXX just for the CSS file...
$lang = "en_US"; // XXX we don't support others yet!
/* =============================================================== */
umask(0);
$go = $_REQUEST['go'];
$first_volume = "v0000";
$new_install = FALSE;
include "lang/$lang.php";
include "$theme/theme.php";
print "<html><head><title>Photo Organizer Installer</title>";
print "<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"$theme/screen.css\">\n";
print "</head><body>";
print "<h3>Photo Organizer Installation/Update Utility</h3>";
/* Sanity Checks */
if (!is_readable("include/config_site.php")) {
print "<h4><font color=\"red\">Please copy include/config_site.php.dist to include/config_site.php and modify it with your site settings! (see installation instructions)</font></h4>\n";
$go = 0;
}
include "include/config.php"; /* Use configured defaults, if possible */
if (!$install_enabled) {
print "<h3><font color=\"red\">Install disabled. please set \$install_enabled=1 in config_site.php if you wish to run the installer.</font></h3>\n";
exit(0);
}
$x = phpversion();
if ($x < "5.4") {
print "<h3>You are running PHP $x but Photo Organizer needs PHP >= 5.4</h3>\n";
$go = 0;
}
if (!$image_repository_path || !is_writable($image_repository_path)) {
print "<h4><font color=\"red\">The image repository '$image_repository_path' is not present or not writable by webserver. Please ensure the <i>\$image_repository_path</i> setting points to a valid directory.</font></h4>\n";
$go = 0;
}
/* =============================================================== */
/* magic quotes and such.. */
if( ini_get('safe_mode') ) {
print "<h4><font color=\"red\">PHP's <i>safe mode</i> is enabled. Photo Organzier will not currently work with safe mode enabled. Please disable it in <i>php.ini</i> and re-load this page.</font></h4>\n";
$go = 0;
}
if( ini_get('display_errors') ) {
print "<h4><font color=\"red\">PHP's <i>display_errors</i> option is enabled. This will break many of PO's pages, on top of being a general security risk. Please disable it in <i>php.ini</i> and re-load this page.</font></h4>\n";
$go = 0;
}
if( ! ini_get('file_uploads') ) {
print "<h4><font color=\"red\">PHP's <i>file_uploads</i> feature is disabled. Without this, it's pretty difficult to import pictures, so we recommend you enable it in <i>php.ini</i>.</font></h4>\n";
}
$filesize = ini_get("upload_max_filesize");
$postsize = ini_get("post_max_size");
$memlimit = ini_get("memory_limit");
if ($filesize > $postsize) $filesize = $postsize;
print "<h4>Note: The current maximum upload file size is $filesize. You may need to increase this. See the <i>upload_max_filesize</i> and <i>post_max_size</i> settings in your <i>php.ini</i> file.</h4>\n";
if ($memlimit != "")
print "<h4>Note: The current memory limit is $memlimit. You may need to increase this. See the <i>memory_limit</i> setting in your <i>php.ini</i> file.</h4>\n";
/* Now test for installed extensions */
if (!extension_loaded("pgsql")) {
print "<h4><font color=\"red\">PHP's PostgreSQL extension is not installed or enabled. The <i>pgsql</i> extension is required.</font></h4>\n";
$go = 0;
}
if (!function_exists("bccomp")) {
print "<h4><font color=\"red\">PHP's BC Math routines are not installed or enabled. The <i>bcmath</i> extension is required.</font></h4>\n";
$go = 0;
}
if (!function_exists("mb_parse_str")) {
print "<h4><font color=\"red\">PHP's Multi-Byte String routines are not installed or enabled. The <i>mbstring</i> extension is required.</font></h4>\n";
$go = 0;
}
if (!function_exists("xml_parser_create")) {
print "<h4><font color=\"red\">PHP's XML extension is not installed or enabled. The <i>XML</i> extension is required.</font></h4>\n";
$go = 0;
}
if (!extension_loaded("memcached")) {
print "<h4>PHP's Memcached extension is not installed or enabled. You can use this extension to cache static database data and speed up many page loads.</h4>\n";
}
$foo = include_once 'Log.php';
if ($foo === FALSE) {
print "<h4><font color=\"red\">The PEAR package <i>Log</i> is not installed or available on the path. Please install it.</font></h4>\n";
$go = 0;
}
if ($external_workers) {
if (!function_exists("posix_getuid")) {
print "<h4><font color=\"red\">PHP's POSIX extension is not installed or enabled. This is needed for the import parallelizer.</font></h4>\n";
$go = 0;
}
if (!function_exists("pcntl_fork")) {
print "<h4><font color=\"yellow\">PHP's PCNTL extension is not installed or enabled. This is needed for the import parallelizer.</font></h4>\n";
}
}
/* Test external utilities */
if ($use_gm) {
if (!is_executable($sys_gm)) {
print "<h4><font color=\"red\">GraphicsMagick is enabled but is not installed at $sys_gm. This utility is optional, but as it has been enabled it must be properly configured. Please ensure it is installed, and that the <i>\$sys_gm</i> and <i>\$use_gm</i> settings are correct.</font></h4>\n";
$go = 0;
}
} else {
if (!is_executable($sys_convert)) {
print "<h4><font color=\"red\">ImageMagick's <i>convert</i> utility is not installed at $sys_convert. This utility is required, so please ensure it is installed, and that the <i>\$sys_convert</i> setting is correct.</font></h4>\n";
$go = 0;
}
if (!is_executable($sys_composite)) {
print "<h4><font color=\"red\">ImageMagick's <i>composite</i> utility is not installed at $sys_composite. This utility is required, so please ensure it is installed, and that the <i>\$sys_composite</i> setting is correct.</font></h4>\n";
$go = 0;
}
}
if (!is_executable($sys_exiftool)) {
print "<h4>ExifTool's <i>exiftool</i> utility is not installed at $sys_exiftool. This utility is required to decode image metadata, so please ensure it is installed, and that the <i>\$sys_exiftool</i> setting is correct.</h4>\n";
$go = 0;
}
if (!is_executable($sys_dcraw)) {
print "<h4>The <i>dcraw</i> utility is not installed at $sys_dcraw. This tool is required if you wish to work with RAW images, although ExifTool can be used in some circumstances. If it is installed, please ensure the <i>\$sys_dcraw</i> setting is correct.</h4>\n";
}
if (!is_executable($sys_gimp)) {
print "<h4>The <i>GIMP</i> is not installed at $sys_gimp. This is required if you wish to work with The GIMP's native .XCF file format. If it is installed, please ensure the <i>\$sys_gimp</i> setting is correct.</h4>\n";
}
if (!is_executable($sys_mplayer)) {
print "<h4><i>mplayer</i> is not installed at $sys_mplayer. This is required if you wish to import/store video files (.avi/.wmv/.asf). If it is installed, please ensure the <i>\$sys_mplayer</i> setting is correct.</h4>\n";
}
if (!is_executable($sys_ps2pdf)) {
print "<h4>The <i>ps2pdf</i> utility is not installed at $sys_ps2pdf. Without this tool you cannot export to PDF. If it is installed, please ensure the <i>\$sys_ps2pdf</i> setting is correct.</h4>\n";
}
if (!is_executable($sys_tar)) {
print "<h4>The <i>tar</i> utility is not installed at $sys_tar. Without this tool you cannot import .tar archives, or export images at all. If it is installed, please ensure the <i>\$sys_tar</i> setting is correct.</h4>\n";
}
if (!is_executable($sys_unzip)) {
print "<h4>The <i>unzip</i> utility is not installed at $sys_unzip. Without this tool you cannot import .zip archives. If it is installed, please ensure the <i>\$sys_unzip</i> setting is correct.</h4>\n";
}
if (!is_executable($sys_7za)) {
print "<h4>The <i>7za</i> utility is not installed at $sys_7za. Without this tool you cannot import .7z archives. If it is installed, please ensure the <i>\$sys_7za</i> setting is correct.</h4>\n";
}
if (isset($db_host)) {
print "<h4><font color=\"red\">Photo Organizer 2.33 and newer use different database configuration mechanisms. You will need to specify this new connection in <i>config_site.php</i> before the upgrade can continue.</font></h4>\n";
print "<blockquote>\n";
print "<h4>Please add the following line to your <i>config_site.php</i> file. For additional examples of database configuration, see <i>config.php</i> for additional examples.</h4>\n";
print "<pre>\$db_dsn = \"host=$db_host port=$db_port dbname=$db_name user=$db_user password=$db_password\";</pre>\n";
print "<h4>Additionally, you will need to erase the \$db_host, \$db_port, \$db_name, \$db_user, and \$db_password settings.</h4>\n";
print "</blockquote>\n";
$go = 0;
}
/* =============================================================== */
/* Kick things off */
if (!$go) {
display_db_form();
print "</html>";
exit(0);
}
ini_set('max_execution_time', 0); /* Unlimited execution time! */
$database = pg_connect($db_dsn);
if ($database === FALSE) {
print "<h3>Database connection failed; Are credentials valid?</h3>";
display_db_form();
print "</html>";
exit(0);
}
$pg_ver = pg_version($database);
if ($pg_ver['server'] < "8.0") {
print "<h3>PostgreSQL 8.0 or newer is required! (Current is $pg_ver[server])</h3>";
print "</html>";
exit(0);
}
# Installation steps:
# su - postgres -c "psql template1 -c \"CREATE USER po_user WITH PASSWORD 'po_password' NOCREATEDB NOCREATEUSER;\""
# su - postgres -c "createdb -O po_user po_db --encoding utf8"
# cp -vr src/* /var/www/html/po/
# cp config_site.inc /var/www/html/po/include/config_site.php, modify it.
# mkdir /tmp/image_repo; chown apache:apache /tmp/image_repo
# tell user to kick off http://site/path/install.php
# su - postgres -c "createlang plpgsql po_db"
$version = po_get_version($database);
print "<h3> Current Photo Organizer DB version: $version</h3>\n";
$res = TRUE;
while ($res) {
$version = po_get_version($database);
$row = $versions[$version];
if (!$row) {
break;
}
print "<h4>Upgrading Photo Organizer DB v $version</h4>\n";
print "<ul>\n";
if (isset($row['file'])) {
print "<li>Upgrading database structure...";
pg_query($database, "begin");
$res = po_process_db_file($database, "sql/$row[file]");
if ($res) {
pg_query($database, "commit");
print "<font color=\"green\">OK</font></li>\n";
} else {
pg_query($database, "rollback");
print "<font color=\"red\">FAILED</font></li>\n";
print "<li><pre>" . pg_last_error($database) . "</pre></li>\n";
}
} elseif (isset($row['function'])) {
$res = $row["function"]($database);
} else {
// ... XXX should never get here!
}
print "</ul>\n";
if ($res === FALSE)
break;
}
if ($res) {
print "<h3> Install/Upgrade to DB version $version complete.</h3>\n";
print "<h3><font color=\"red\" IMPORTANT: Set \$install_enabled=0 in config_site.php to disable installer.</font></h3>\n";
print "<h3> If you find PO useful, please consider sending its maintainer an email or subscribing to its Freshmeat entry. This helps gauge the installed base and outside interest. </h3>";
} else {
print "</ul>\n";
print "<h3> Correct the above errors, and try again. We will pick up where we left off.</h3>\n";
}
/*********/
print "</body></html>";
exit(0);
/* =============================================================== */
?>