1
0

Merge branch 'master' of github.com:brentil/gallery3-contrib

Conflicts:
	modules/moduleupdates/controllers/admin_moduleupdates.php
	modules/moduleupdates/helpers/moduleupdates_event.php
	modules/moduleupdates/helpers/moduleupdates_installer.php
	modules/moduleupdates/module.info
	modules/moduleupdates/views/admin_moduleupdates.html.php
This commit is contained in:
brentil 2011-06-24 18:10:13 -04:00
commit cda590be33
3882 changed files with 198004 additions and 19876 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.DS_Store
tmp
*~
*.swp

BIN
3.0/client/Java/Demo.class Normal file

Binary file not shown.

50
3.0/client/Java/Demo.java Normal file
View File

@ -0,0 +1,50 @@
import java.util.ArrayList;
import java.util.List;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import com.google.gson.Gson;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
public class Demo {
public static final String BASE_URL = "http://example.com/gallery3/index.php";
public static final String USERNAME = "admin";
public static final String PASSWORD = "admin";
public static void main(String[] argv) throws java.io.UnsupportedEncodingException, java.io.IOException {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
Gson gson = new Gson();
// Get the REST API key
HttpPost post = new HttpPost(BASE_URL + "/rest");
ArrayList<NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("user", USERNAME));
nvps.add(new BasicNameValuePair("password", USERNAME));
post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
response = httpclient.execute(post);
String api_key = gson.fromJson(new BufferedReader(
new InputStreamReader(response.getEntity().getContent())).readLine(), String.class);
System.out.println("API Key:" + api_key);
// Get the JSON representation of the root album, which we know has id 1
HttpGet get = new HttpGet(BASE_URL + "/rest/item/1");
get.setHeader("X-Gallery-Request-Method", "GET");
get.setHeader("X-Gallery-Request-Key", api_key);
response = httpclient.execute(get);
System.out.println(
"Response: " + new BufferedReader(new InputStreamReader(response.getEntity().getContent())).readLine());
}
}

10
3.0/client/Java/README Normal file
View File

@ -0,0 +1,10 @@
This is very, very rough sample code for how to do some Java REST
requests. To run this code:
1) Edit Demo.java and set the BASE_URL to your Gallery3 install.
2) Edit USERNAME and PASSWORD as appropriate
3) In a shell, do "sh build.sh"
4) In a shell, do "sh run.sh"
Note that there is NO error checking, so if something goes wrong
you'll have to debug it.

1
3.0/client/Java/build.sh Normal file
View File

@ -0,0 +1 @@
javac -classpath lib/httpclient-4.0.1.jar:lib/httpcore-4.0.1.jar:lib/gson-1.4.jar Demo.java

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
3.0/client/Java/run.sh Normal file
View File

@ -0,0 +1 @@
java -classpath lib/httpclient-4.0.1.jar:lib/httpcore-4.0.1.jar:lib/commons-logging-api-1.1.1.jar:lib/gson-1.4.jar:. Demo

2
3.0/client/PHP/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# local file to provide configuration for the client code. See README.
local_config.php

View File

@ -111,6 +111,10 @@ class Gallery3 {
* @return object Gallery3
*/
public function create($url, $token) {
if (!is_string($url)) {
throw new Gallery3_Exception("Invalid url: " . var_export($url));
}
$response = Gallery3_Helper::request(
"post", $url, $token, array("entity" => $this->data->entity), $this->file);
$this->url = $response->url;
@ -125,10 +129,16 @@ class Gallery3 {
* @return object Gallery3
*/
public function save() {
$response = Gallery3_Helper::request(
"put", $this->url, $this->token,
array("entity" => array_diff((array)$this->data->entity, $this->original_entity),
"members" => $this->data->members));
$data = array();
$data["entity"] = array_diff((array)$this->data->entity, $this->original_entity);
if (isset($this->data->members)) {
$data["members"] = $this->data->members;
}
if ($this->file) {
$response = Gallery3_Helper::request("put", $this->url, $this->token, $data, $this->file);
} else {
$response = Gallery3_Helper::request("put", $this->url, $this->token, $data);
}
return $this->load();
}
@ -153,7 +163,7 @@ class Gallery3 {
public function load() {
$response = Gallery3_Helper::request("get", $this->url, $this->token);
$this->data = $response;
$this->original_entity = (array)$response->entity;
$this->original_entity = isset($response->entity) ? (array)$response->entity : null;
return $this;
}
}
@ -176,6 +186,7 @@ class Gallery3_Helper {
switch ($req->getResponseCode()) {
case 200:
case 201:
return json_decode($req->getResponseBody());
case 403:

4
3.0/client/PHP/README Normal file
View File

@ -0,0 +1,4 @@
# Create a local file called local_config.php and add the following content:
$SITE_URL = "http://<your domain>/gallery3/index.php/rest";
$USER = "<user admin Id>";
$PASSWORD = "<user admin password>";

View File

@ -13,6 +13,7 @@ alert("Connect to $SITE_URL");
$auth = Gallery3::login($SITE_URL, $USER, $PASSWORD);
$root = Gallery3::factory("$SITE_URL/item/1", $auth);
$tags = Gallery3::factory("$SITE_URL/tags", $auth);
$comments = Gallery3::factory("$SITE_URL/comments", $auth);
$tag = Gallery3::factory()
->set("name", "My Tag")
@ -38,13 +39,26 @@ for ($i = 0; $i < 2; $i++) {
->set("type", "photo")
->set("name", "Sample Photo.png")
->set("title", "Sample Photo")
->set_file("gallery.png")
->set_file("test1.png")
->create($album->url, $auth);
alert("Uploaded photo: <b>{$photo->url}</b>");
}
$album->load();
alert("Album members: <b>" . join(", ", $album->data->members) . "</b>");
alert("Replace the data file");
$photo->set_file("test2.png")
->save();
$comment = Gallery3::factory()
->set("item", $album->data->members[0])
->set("type", "comment")
->set("text", "This is a random comment-- whee!")
->create($comments->url, $auth);
alert("Comment: <b>{$comment->url}</b>");
alert("Reorder the album");
$album
->set_members(array($album->data->members[1], $album->data->members[0]))
@ -85,7 +99,6 @@ $tag_relationship2->delete();
$tag->load();
alert("1 remaining tag: <b>{$tag->data->relationships->items->members[0]}</b>");
alert("Delete the album and tag");
$album->delete();
$tag->delete();
@ -93,7 +106,7 @@ $tag->delete();
alert("Done!");
function alert($msg) {
print "$msg <br/>";
print "$msg <br/>\n";
flush();
}
?>

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

BIN
3.0/client/PHP/test2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -0,0 +1,57 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class Admin_adsense_Controller extends Admin_Controller {
public function index() {
$view = new Admin_View("admin.html");
$view->page_title = t("Adsense settings");
$view->content = new View("admin_adsense.html");
$view->content->form = $this->_get_admin_form();
print $view;
}
public function save() {
access::verify_csrf();
$form = $this->_get_admin_form();
if ($form->validate()) {
module::set_var("adsense", "code", $form->adsense->code->value);
module::set_var("adsense", "location", $form->adsense->location->value);
message::success(t("Adsense settings updated"));
url::redirect("admin/adsense");
} else {
print $form;
}
}
private function _get_admin_form() {
$form = new Forge("admin/adsense/save", "", "post", array("id" => "g-adsense-admin-form"));
$adsense_settings = $form->group("adsense")->label(t("Adsense settings"));
$adsense_settings->textarea("code")->label(t("Adsense code"))
->value(module::get_var("adsense", "code"));
$adsense_settings->dropdown("location")
->label(t("Where should the ads be displayed?"))
->options(array("header" => t("In the header"),
"sidebar" => t("In the sidebar"),
"footer" => t("In the footer")))
->selected(module::get_var("adsense", "location"));
$adsense_settings->submit("save")->value(t("Save"));
return $form;
}
}

View File

@ -0,0 +1,39 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class adsense_block_Core {
static function get_site_list() {
return array("adsense" => t("Adsense"));
}
static function get($block_id, $theme) {
$block = "";
switch ($block_id) {
case "adsense":
if (module::get_var("adsense", "location") == "sidebar") {
$block = new Block();
$block->css_id = "g-adsense";
$block->title = t("Adsense");
$block->content = new View("adsense_block.html");
}
break;
}
return $block;
}
}

View File

@ -0,0 +1,28 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class adsense_event_Core {
static function admin_menu($menu, $theme) {
$menu->get("settings_menu")
->append(Menu::factory("link")
->id("adsense_menu")
->label(t("Adsense"))
->url(url::site("admin/adsense")));
}
}

View File

@ -0,0 +1,54 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
//header_bottom or footer
class adsense_theme {
static function header_bottom($theme) {
if(module::get_var("adsense","location") == "header") {
$code = module::get_var("adsense", "code");
if (!$code) {
return;
}
$google_code = '
<script type="text/javascript">' . $code . '</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>';
return $google_code;
}
}
static function footer($theme) {
if(module::get_var("adsense","location") == "footer") {
$code = module::get_var("adsense", "code");
if (!$code) {
return;
}
$google_code = '
<script type="text/javascript">' . $code . '</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>';
return $google_code;
}
}
}

View File

@ -0,0 +1,3 @@
name = "Adsense"
description = "Display Google Adsense ads"
version = 1

View File

@ -0,0 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.") ?>
<div class="g-block">
<h1> <?= t("Adsense settings") ?> </h1>
<div class="g-block-content">
<?= $form ?>
</div>
</div>

View File

@ -0,0 +1,17 @@
<?php
defined("SYSPATH") or die("No direct script access.");
if(module::get_var("adsense","location") == "sidebar") {
$code = module::get_var("adsense", "code");
if (!$code) {
return;
}
$google_code = '
<script type="text/javascript">' . $code . '</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>';
echo $google_code;
}
?>

View File

@ -0,0 +1,152 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class albumpassword_Controller extends Controller {
public function assign($id) {
// Display prompt for assigning a new password.
// Make sure user has view/edit access for this item.
$item = ORM::factory("item", $id);
access::required("view", $item);
access::required("edit", $item);
// Create the page.
$view = new View("assignpassword.html");
$view->form = $this->_get_password_form($id);
print $view;
}
public function login() {
// Display prompt to allow visitors to use their passwords.
// Create the page.
$view = new View("loginpassword.html");
$view->form = $this->_get_login_form();
print $view;
}
public function remove($id) {
// Remove a password from an album
// Make sure user has view/edit privileges for this item
$item = ORM::factory("item", $id);
access::required("view", $item);
access::required("edit", $item);
// Check for and delete the password.
$existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $id)->find();
if ($existing_password->loaded()) {
db::build()->delete("items_albumpasswords")->where("album_id", "=", $id)->execute();
message::success(t("Password Removed."));
}
// Redirect the user back to the album.
url::redirect(url::abs_site("albums/" . $id));
}
public function savepassword() {
// Save a newly assigned password.
// Prevent Cross Site Request Forgery
access::verify_csrf();
// Convert submitted data to local variables.
$album_id = Input::instance()->post("item_id");
$album_password = Input::instance()->post("assignpassword_password");
// Check for, and remove, any existing passwords.
$existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $album_id)->find();
if ($existing_password->loaded()) {
db::build()->delete("items_albumpasswords")->where("album_id", "=", $album_id)->execute();
}
// Save the new password.
$new_password = ORM::factory("items_albumpassword");
$new_password->album_id = $album_id;
$new_password->password = $album_password;
$new_password->save();
// Display a success message and close the dialog.
message::success(t("Password saved."));
json::reply(array("result" => "success"));
}
public function logout() {
// Delete a stored password cookie.
cookie::delete("g3_albumpassword");
url::redirect(url::abs_site("albums/1"));
}
public function checkpassword() {
// Check that a password is valid, then store in a browser cookie.
// Prevent Cross Site Request Forgery
access::verify_csrf();
// Convert submitted data to local variables.
$album_password = Input::instance()->post("albumpassword_password");
// See if the submitted password matches any in the database.
$existing_password = ORM::factory("items_albumpassword")
->where("password", "=", $album_password)
->find_all();
if (count($existing_password) > 0) {
// If the password if valid, then store it, and display a success message.
// If not, close the dialog and display a rejected message.
cookie::set("g3_albumpassword", $album_password);
message::success(t("Password Accepted."));
json::reply(array("result" => "success"));
} else {
message::error(t("Password Rejected."));
json::reply(array("result" => "success"));
}
}
private function _get_password_form($id) {
// Generate a form for assigning a new password.
$form = new Forge("albumpassword/savepassword", "", "post",
array("id" => "g-assign-password-form"));
$assignpassword_group = $form->group("Enter Password")
->label(t("Enter Password:"));
$assignpassword_group->hidden("item_id")->value($id);
$assignpassword_group->input("assignpassword_password")
->id('assignpassword_password')
->label(t("Password:"));
$form->submit("save_password")->value(t("Save"));
// Return the newly generated form.
return $form;
}
private function _get_login_form($id) {
// Generate a form for allowing visitors to enter in their passwords.
$form = new Forge("albumpassword/checkpassword", "", "post",
array("id" => "g-login-password-form"));
$assignpassword_group = $form->group("Enter Password")
->label(t("Enter Password:"));
$assignpassword_group->input("albumpassword_password")
->id('albumpassword_password')
->label(t("Password:"));
$form->submit("login_password")->value(t("Login"));
// Return the newly generated form.
return $form;
}
}

View File

@ -0,0 +1,53 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class item extends item_Core {
static function viewable($model) {
// Hide the contents of a password protected album,
// Unless the current user is an admin, or the albums owner.
$model = item_Core::viewable($model);
$album_item = ORM::factory("item")->where("id", "=", $model->id)->find();
// Figure out if the user can access this album.
$deny_access = false;
$existing_password = ORM::factory("items_albumpassword")->where("album_id", "=", $model->id)->find();
if ($existing_password->loaded()) {
if ((cookie::get("g3_albumpassword") != $existing_password->password) &&
(identity::active_user()->id != $album_item->owner_id))
$deny_access = true;
}
// set access::DENY if necessary.
if ($deny_access == true) {
$view_restrictions = array();
if (!identity::active_user()->admin) {
foreach (identity::group_ids_for_active_user() as $id) {
$view_restrictions[] = array("items.view_$id", "=", access::DENY);
}
}
}
if (count($view_restrictions)) {
$model->and_open()->merge_or_where($view_restrictions)->close();
}
return $model;
}
}

View File

@ -0,0 +1,104 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class albumpassword_event_Core {
static function site_menu($menu, $theme) {
// Add menu options for Adding / Removing / Using passwords to the menu.
// If this page doesn't belong to an item, don't display the menu.
if (!$theme->item()) {
return;
}
$item = $theme->item();
// If there isn't currently a password stored in the cookie,
// then display the enter password link.
if (cookie::get("g3_albumpassword") == "") {
$menu->append(Menu::factory("dialog")
->id("albumpassword_login")
->css_id("g-album-password-login")
->url(url::site("albumpassword/login"))
->label(t("Enter password")));
} else {
// If a password has been entered already
// display the log out link, and links to the protected albums
$menu->append(Menu::factory("submenu")
->id("albumpassword_protected")
->css_id("g-album-password-protected")
->label(t("Protected albums")));
$menu->get("albumpassword_protected")
->append(Menu::factory("link")
->id("albumpassword_logout")
->css_id("g-album-password-logout")
->url(url::site("albumpassword/logout"))
->label(t("Clear password")));
$existing_password = ORM::factory("items_albumpassword")
->where("password", "=", cookie::get("g3_albumpassword"))
->find_all();
if (count($existing_password) > 0) {
$counter = 0;
while ($counter < count($existing_password)) {
$item_album = ORM::factory("item")->where("id", "=", $existing_password[$counter]->album_id)->find();
$menu->get("albumpassword_protected")
->append(Menu::factory("link")
->id("albumpassword_album" . $counter)
->label(html::purify($item_album->title))
->css_id("g-album-password-album" . $counter)
->url(url::abs_site("{$item_album->type}s/{$item_album->id}")));
$counter++;
}
}
}
// If this is an album without a password, display a link for assigning one.
// If this is an album with a password, display a link to remove it.
if ($item->is_album()) {
if ((access::can("view", $item)) && (access::can("edit", $item))) {
$existing_password = ORM::factory("items_albumpassword")
->where("album_id", "=", $item->id)
->find_all();
if (count($existing_password) > 0) {
$menu->get("options_menu")
->append(Menu::factory("link")
->id("albumpassword_remove")
->label(t("Remove password"))
->css_id("g-album-password-remove")
->url(url::site("albumpassword/remove/" . $item->id)));
} else {
$menu->get("options_menu")
->append(Menu::factory("dialog")
->id("albumpassword_assign")
->label(t("Assign password"))
->css_id("g-album-password-assign")
->url(url::site("albumpassword/assign/" . $item->id)));
}
}
}
}
static function item_deleted($item) {
// If an album is deleted, remove any associated passwords.
$existingPasswords = ORM::factory("items_albumpassword")
->where("album_id", "=", $item->id)
->find_all();
if (count($existingPasswords) > 0) {
db::build()->delete("items_albumpassword")->where("album_id", "=", $item->id)->execute();
}
}
}

View File

@ -0,0 +1,42 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class albumpassword_installer {
static function install() {
// Create a table to store passwords in.
$db = Database::instance();
$db->query("CREATE TABLE IF NOT EXISTS {items_albumpasswords} (
`id` int(9) NOT NULL auto_increment,
`album_id` int(9) NOT NULL,
`password` varchar(64) NOT NULL,
PRIMARY KEY (`id`))
DEFAULT CHARSET=utf8;");
// Set the module's version number.
module::set_version("albumpassword", 1);
}
static function uninstall() {
// Delete the password table before uninstalling.
$db = Database::instance();
$db->query("DROP TABLE IF EXISTS {items_albumpassword};");
module::delete("albumpassword");
}
}

View File

@ -1,4 +1,4 @@
<?php defined("SYSPATH") or die("No direct script access.")
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
@ -17,8 +17,5 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
?>
<div class="g-block">
<h2>Thankyou for your order</h2>
You will be contacted soon to arrange payment and delivery.
</div>
class Items_Albumpassword_Model extends ORM {
}

View File

@ -0,0 +1,3 @@
name = "Album Password"
description = "Restrict access to individual albums."
version = 1

View File

@ -0,0 +1,24 @@
<script type="text/javascript">
function ajaxify_login_reset_form() {
$("#g-login form").ajaxForm({
dataType: "json",
success: function(data) {
if (data.form) {
$("#g-login form").replaceWith(data.form);
ajaxify_login_reset_form();
}
if (data.result == "success") {
$("#g-dialog").dialog("close");
window.location.reload();
}
}
});
};
</script>
<div id="g-assign-password">
<ul>
<li id="g-assign-password-form">
<?= $form ?>
</li>
</ul>
</div>

View File

@ -0,0 +1,24 @@
<script type="text/javascript">
function ajaxify_login_reset_form() {
$("#g-login form").ajaxForm({
dataType: "json",
success: function(data) {
if (data.form) {
$("#g-login form").replaceWith(data.form);
ajaxify_login_reset_form();
}
if (data.result == "success") {
$("#g-dialog").dialog("close");
window.location.reload();
}
}
});
};
</script>
<div id="g-login-password">
<ul>
<li id="g-login-password-form">
<?= $form ?>
</li>
</ul>
</div>

View File

@ -0,0 +1,37 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class albumtree_block_Core {
static function get_site_list() {
return array("albumtree" => t("Album tree"));
}
static function get($block_id) {
$block = new Block();
switch ($block_id) {
case "albumtree":
$block->css_id = "g-albumtree";
$block->title = t("Album Tree");
$block->content = new View("albumtree_block.html");
$block->content->root = item::root();
break;
}
return $block;
}
}

View File

@ -0,0 +1,3 @@
name = "Album Tree"
description = "Provides a block in the sidebar with quick links to all other albums."
version = 1

View File

@ -0,0 +1,24 @@
<?php defined("SYSPATH") or die("No direct script access.") ?>
<select onchange="window.location='<?= url::site("items/__ID__")?>'.replace('__ID__', this.value)">
<? // We'll keep track of the list of items that we want to display in a stack ?>
<? $stack = array(array(0, $root)) ?>
<? // While there are still items to show, pick the next one and show it ?>
<? while ($stack): ?>
<? list($level, $album) = array_pop($stack) ?>
<option value="<?= $album->id ?>"><?= str_repeat("&nbsp;&nbsp;", $level) ?><?= $album->title ?></option>
<? // Then take all of that album's children and put them next on the stack. ?>
<? $tmp = array(); ?>
<? foreach ($album->children(null, null, array(array("type", "=", "album"))) as $child): ?>
<? $tmp[] = array($level + 1, $child) ?>
<? endforeach ?>
<? // Since we'll pull them off the stack in the opposite order that we put them on, ?>
<? // and the order that we put them on is the order in which we want to display them, ?>
<? // We need to reverse the order of the children on the stack ?>
<? if ($tmp): ?>
<? $stack = array_merge($stack, array_reverse($tmp)) ?>
<? endif ?>
<? endwhile ?>
</select>

View File

@ -0,0 +1,68 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class autorotate {
static function rotate_item($item) {
require_once(MODPATH . 'autorotate/lib/pel/PelDataWindow.php');
require_once(MODPATH . 'autorotate/lib/pel/PelJpeg.php');
require_once(MODPATH . 'autorotate/lib/pel/PelTiff.php');
// Only try to rotate photos based on EXIF
if ($item->is_photo() && $item->mime_type == "image/jpeg") {
require_once(MODPATH . "exif/lib/exif.php");
$exif_raw = read_exif_data_raw($item->file_path(), false);
if (isset($exif_raw['ValidEXIFData'])) {
$orientation = $exif_raw["IFD0"]["Orientation"];
$degrees = 0;
if ($orientation == '3: Upside-down') {
$degrees = 180;
}
else if ($orientation == '8: 90 deg CW') {
$degrees = -90;
}
else if ($orientation == '6: 90 deg CCW') {
$degrees = 90;
}
if($degrees) {
$tmpfile = tempnam(TMPPATH, "rotate");
gallery_graphics::rotate($item->file_path(), $tmpfile, array("degrees" => $degrees));
// Update EXIF info
$data = new PelDataWindow(file_get_contents($tmpfile));
if (PelJpeg::isValid($data)) {
$jpeg = $file = new PelJpeg();
$jpeg->load($data);
$exif = $jpeg->getExif();
if($exif !== null) {
$tiff = $exif->getTiff();
$ifd0 = $tiff->getIfd();
$orientation = $ifd0->getEntry(PelTag::ORIENTATION);
$orientation->setValue(1);
file_put_contents($tmpfile, $file->getBytes());
}
}
$item->set_data_file($tmpfile);
$item->save();
unlink($tmpfile);
}
}
}
return;
}
}

View File

@ -0,0 +1,32 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class autorotate_event_Core {
// The assumption is that the exception was logged at a lower level, but we
// don't want to screw up the processing that was generating the notification
// so we don't pass the exception up the call stack
static function item_created($item) {
try {
autorotate::rotate_item($item);
} catch (Exception $e) {
Kohana_Log::add("error", "@todo autorotate_event::item_created() failed");
Kohana_Log::add("error", $e->getMessage() . "\n" . $e->getTraceAsString());
}
}
}

View File

@ -0,0 +1,42 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class autorotate_installer {
static function install() {
module::set_version("autorotate", 2);
}
static function upgrade($version) {
if ($version == 1) {
module::set_version("autorotate", $version = 2);
}
}
static function deactivate() {
site_status::clear("autorotate_needs_exif");
}
static function can_activate() {
$messages = array();
if (!module::is_active("exif")) {
$messages["warn"][] = t("The autorotate module requires the EXIF module.");
}
return $messages;
}
}

View File

@ -0,0 +1,337 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: Pel.php 463 2006-11-18 22:25:24Z mgeisler $ */
/**
* Miscellaneous stuff for the overall behavior of PEL.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 463 $
* @date $Date: 2006-11-18 23:25:24 +0100 (Sat, 18 Nov 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/* Initialize Gettext, if available. This must be done before any
* part of PEL calls Pel::tra() or Pel::fmt() --- this is ensured if
* every piece of code using those two functions require() this file.
*
* If Gettext is not available, wrapper functions will be created,
* allowing PEL to function, but without any translations.
*
* The PEL translations are stored in './locale'. It is important to
* use an absolute path here because the lookups will be relative to
* the current directory. */
if (function_exists('dgettext')) {
bindtextdomain('pel', dirname(__FILE__) . '/locale');
} else {
/**
* Pretend to lookup a message in a specific domain.
*
* This is just a stub which will return the original message
* untranslated. The function will only be defined if the Gettext
* extension has not already defined it.
*
* @param string $domain the domain.
*
* @param string $str the message to be translated.
*
* @return string the original, untranslated message.
*/
function dgettext($domain, $str) {
return $str;
}
}
/**
* Class with miscellaneous static methods.
*
* This class will contain various methods that govern the overall
* behavior of PEL.
*
* Debugging output from PEL can be turned on and off by assigning
* true or false to {@link Pel::$debug}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class Pel {
/**
* Flag for controlling debug information.
*
* The methods producing debug information ({@link debug()} and
* {@link warning()}) will only output something if this variable is
* set to true.
*
* @var boolean
*/
private static $debug = false;
/**
* Flag for strictness of parsing.
*
* If this variable is set to true, then most errors while loading
* images will result in exceptions being thrown. Otherwise a
* warning will be emitted (using {@link Pel::warning}) and the
* exceptions will be appended to {@link Pel::$exceptions}.
*
* Some errors will still be fatal and result in thrown exceptions,
* but an effort will be made to skip over as much garbage as
* possible.
*
* @var boolean
*/
private static $strict = false;
/**
* Stored exceptions.
*
* When {@link Pel::$strict} is set to false exceptions will be
* accumulated here instead of being thrown.
*/
private static $exceptions = array();
/**
* Return list of stored exceptions.
*
* When PEL is parsing in non-strict mode, it will store most
* exceptions instead of throwing them. Use this method to get hold
* of them when a call returns.
*
* Code for using this could look like this:
*
* <code>
* Pel::setStrictParsing(true);
* Pel::clearExceptions();
*
* $jpeg = new PelJpeg($file);
*
* // Check for exceptions.
* foreach (Pel::getExceptions() as $e) {
* printf("Exception: %s\n", $e->getMessage());
* if ($e instanceof PelEntryException) {
* // Warn about entries that couldn't be loaded.
* printf("Warning: Problem with %s.\n",
* PelTag::getName($e->getType(), $e->getTag()));
* }
* }
* </code>
*
* This gives applications total control over the amount of error
* messages shown and (hopefully) provides the necessary information
* for proper error recovery.
*
* @return array the exceptions.
*/
static function getExceptions() {
return self::$exceptions;
}
/**
* Clear list of stored exceptions.
*
* Use this function before a call to some method if you intend to
* check for exceptions afterwards.
*/
static function clearExceptions() {
self::$exceptions = array();
}
/**
* Conditionally throw an exception.
*
* This method will throw the passed exception when strict parsing
* in effect (see {@link setStrictParsing()}). Otherwise the
* exception is stored (it can be accessed with {@link
* getExceptions()}) and a warning is issued (with {@link
* Pel::warning}).
*
* @param PelException $e the exceptions.
*/
static function maybeThrow(PelException $e) {
if (self::$strict) {
throw $e;
} else {
self::$exceptions[] = $e;
self::warning('%s (%s:%s)', $e->getMessage(),
basename($e->getFile()), $e->getLine());
}
}
/**
* Enable/disable strict parsing.
*
* If strict parsing is enabled, then most errors while loading
* images will result in exceptions being thrown. Otherwise a
* warning will be emitted (using {@link Pel::warning}) and the
* exceptions will be stored for later use via {@link
* getExceptions()}.
*
* Some errors will still be fatal and result in thrown exceptions,
* but an effort will be made to skip over as much garbage as
* possible.
*
* @param boolean $flag use true to enable strict parsing, false to
* diable.
*/
function setStrictParsing($flag) {
self::$strict = $flag;
}
/**
* Get current setting for strict parsing.
*
* @return boolean true if strict parsing is in effect, false
* otherwise.
*/
function getStrictParsing() {
return self::$strict;
}
/**
* Enable/disable debugging output.
*
* @param boolean $flag use true to enable debug output, false to
* diable.
*/
function setDebug($flag) {
self::$debug = $flag;
}
/**
* Get current setting for debug output.
*
* @return boolean true if debug is enabled, false otherwise.
*/
function getDebug() {
return self::$debug;
}
/**
* Conditionally output debug information.
*
* This method works just like printf() except that it always
* terminates the output with a newline, and that it only outputs
* something if the {@link Pel::$debug} is true.
*
* @param string $format the format string.
*
* @param mixed $args,... any number of arguments can be given. The
* arguments will be available for the format string as usual with
* sprintf().
*/
static function debug() {
if (self::$debug) {
$args = func_get_args();
$str = array_shift($args);
vprintf($str . "\n", $args);
}
}
/**
* Conditionally output a warning.
*
* This method works just like printf() except that it prepends the
* output with the string 'Warning: ', terminates the output with a
* newline, and that it only outputs something if the PEL_DEBUG
* defined to some true value.
*
* @param string $format the format string.
*
* @param mixed $args,... any number of arguments can be given. The
* arguments will be available for the format string as usual with
* sprintf().
*/
static function warning() {
if (self::$debug) {
$args = func_get_args();
$str = array_shift($args);
vprintf('Warning: ' . $str . "\n", $args);
}
}
/**
* Translate a string.
*
* This static function will use Gettext to translate a string. By
* always using this function for static string one is assured that
* the translation will be taken from the correct text domain.
* Dynamic strings should be passed to {@link fmt} instead.
*
* @param string the string that should be translated.
*
* @return string the translated string, or the original string if
* no translation could be found.
*/
static function tra($str) {
return dgettext('pel', $str);
}
/**
* Translate and format a string.
*
* This static function will first use Gettext to translate a format
* string, which will then have access to any extra arguments. By
* always using this function for dynamic string one is assured that
* the translation will be taken from the correct text domain. If
* the string is static, use {@link tra} instead as it will be
* faster.
*
* @param string $format the format string. This will be translated
* before being used as a format string.
*
* @param mixed $args,... any number of arguments can be given. The
* arguments will be available for the format string as usual with
* sprintf().
*
* @return string the translated string, or the original string if
* no translation could be found.
*/
static function fmt() {
$args = func_get_args();
$str = array_shift($args);
return vsprintf(dgettext('pel', $str), $args);
}
}
?>

View File

@ -0,0 +1,397 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelConvert.php 387 2005-10-05 11:02:52Z mgeisler $ */
/**
* Routines for converting back and forth between bytes and integers.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 387 $
* @date $Date: 2005-10-05 13:02:52 +0200 (Wed, 05 Oct 2005) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Conversion functions to and from bytes and integers.
*
* The functions found in this class are used to convert bytes into
* integers of several sizes ({@link bytesToShort}, {@link
* bytesToLong}, and {@link bytesToRational}) and convert integers of
* several sizes into bytes ({@link shortToBytes} and {@link
* longToBytes}).
*
* All the methods are static and they all rely on an argument that
* specifies the byte order to be used, this must be one of the class
* constants {@link LITTLE_ENDIAN} or {@link BIG_ENDIAN}. These
* constants will be referred to as the pseudo type PelByteOrder
* throughout the documentation.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelConvert {
/**
* Little-endian (Intel) byte order.
*
* Data stored in little-endian byte order store the least
* significant byte first, so the number 0x12345678 becomes 0x78
* 0x56 0x34 0x12 when stored with little-endian byte order.
*/
const LITTLE_ENDIAN = true;
/**
* Big-endian (Motorola) byte order.
*
* Data stored in big-endian byte order store the most significant
* byte first, so the number 0x12345678 becomes 0x12 0x34 0x56 0x78
* when stored with big-endian byte order.
*/
const BIG_ENDIAN = false;
/**
* Convert an unsigned short into two bytes.
*
* @param int the unsigned short that will be converted. The lower
* two bytes will be extracted regardless of the actual size passed.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*
* @return string the bytes representing the unsigned short.
*/
static function shortToBytes($value, $endian) {
if ($endian == self::LITTLE_ENDIAN)
return chr($value) . chr($value >> 8);
else
return chr($value >> 8) . chr($value);
}
/**
* Convert a signed short into two bytes.
*
* @param int the signed short that will be converted. The lower
* two bytes will be extracted regardless of the actual size passed.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*
* @return string the bytes representing the signed short.
*/
static function sShortToBytes($value, $endian) {
/* We can just use shortToBytes, since signed shorts fits well
* within the 32 bit signed integers used in PHP. */
return self::shortToBytes($value, $endian);
}
/**
* Convert an unsigned long into four bytes.
*
* Because PHP limits the size of integers to 32 bit signed, one
* cannot really have an unsigned integer in PHP. But integers
* larger than 2^31-1 will be promoted to 64 bit signed floating
* point numbers, and so such large numbers can be handled too.
*
* @param int the unsigned long that will be converted. The
* argument will be treated as an unsigned 32 bit integer and the
* lower four bytes will be extracted. Treating the argument as an
* unsigned integer means that the absolute value will be used. Use
* {@link sLongToBytes} to convert signed integers.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*
* @return string the bytes representing the unsigned long.
*/
static function longToBytes($value, $endian) {
/* We cannot convert the number to bytes in the normal way (using
* shifts and modulo calculations) because the PHP operator >> and
* function chr() clip their arguments to 2^31-1, which is the
* largest signed integer known to PHP. But luckily base_convert
* handles such big numbers. */
$hex = str_pad(base_convert($value, 10, 16), 8, '0', STR_PAD_LEFT);
if ($endian == self::LITTLE_ENDIAN)
return (chr(hexdec($hex{6} . $hex{7})) .
chr(hexdec($hex{4} . $hex{5})) .
chr(hexdec($hex{2} . $hex{3})) .
chr(hexdec($hex{0} . $hex{1})));
else
return (chr(hexdec($hex{0} . $hex{1})) .
chr(hexdec($hex{2} . $hex{3})) .
chr(hexdec($hex{4} . $hex{5})) .
chr(hexdec($hex{6} . $hex{7})));
}
/**
* Convert a signed long into four bytes.
*
* @param int the signed long that will be converted. The argument
* will be treated as a signed 32 bit integer, from which the lower
* four bytes will be extracted.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*
* @return string the bytes representing the signed long.
*/
static function sLongToBytes($value, $endian) {
/* We can convert the number into bytes in the normal way using
* shifts and modulo calculations here (in contrast with
* longToBytes) because PHP automatically handles 32 bit signed
* integers for us. */
if ($endian == self::LITTLE_ENDIAN)
return (chr($value) .
chr($value >> 8) .
chr($value >> 16) .
chr($value >> 24));
else
return (chr($value >> 24) .
chr($value >> 16) .
chr($value >> 8) .
chr($value));
}
/**
* Extract an unsigned byte from a string of bytes.
*
* @param string the bytes.
*
* @param int the offset. The byte found at the offset will be
* returned as an integer. The must be at least one byte available
* at offset.
*
* @return int the unsigned byte found at offset, e.g., an integer
* in the range 0 to 255.
*/
static function bytesToByte($bytes, $offset) {
return ord($bytes{$offset});
}
/**
* Extract a signed byte from bytes.
*
* @param string the bytes.
*
* @param int the offset. The byte found at the offset will be
* returned as an integer. The must be at least one byte available
* at offset.
*
* @return int the signed byte found at offset, e.g., an integer in
* the range -128 to 127.
*/
static function bytesToSByte($bytes, $offset) {
$n = self::bytesToByte($bytes, $offset);
if ($n > 127)
return $n - 256;
else
return $n;
}
/**
* Extract an unsigned short from bytes.
*
* @param string the bytes.
*
* @param int the offset. The short found at the offset will be
* returned as an integer. There must be at least two bytes
* available beginning at the offset given.
*
* @return int the unsigned short found at offset, e.g., an integer
* in the range 0 to 65535.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*/
static function bytesToShort($bytes, $offset, $endian) {
if ($endian == self::LITTLE_ENDIAN)
return (ord($bytes{$offset+1}) * 256 +
ord($bytes{$offset}));
else
return (ord($bytes{$offset}) * 256 +
ord($bytes{$offset+1}));
}
/**
* Extract a signed short from bytes.
*
* @param string the bytes.
*
* @param int the offset. The short found at offset will be returned
* as an integer. There must be at least two bytes available
* beginning at the offset given.
*
* @return int the signed byte found at offset, e.g., an integer in
* the range -32768 to 32767.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*/
static function bytesToSShort($bytes, $offset, $endian) {
$n = self::bytesToShort($bytes, $offset, $endian);
if ($n > 32767)
return $n - 65536;
else
return $n;
}
/**
* Extract an unsigned long from bytes.
*
* @param string the bytes.
*
* @param int the offset. The long found at offset will be returned
* as an integer. There must be at least four bytes available
* beginning at the offset given.
*
* @return int the unsigned long found at offset, e.g., an integer
* in the range 0 to 4294967295.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*/
static function bytesToLong($bytes, $offset, $endian) {
if ($endian == self::LITTLE_ENDIAN)
return (ord($bytes{$offset+3}) * 16777216 +
ord($bytes{$offset+2}) * 65536 +
ord($bytes{$offset+1}) * 256 +
ord($bytes{$offset}));
else
return (ord($bytes{$offset}) * 16777216 +
ord($bytes{$offset+1}) * 65536 +
ord($bytes{$offset+2}) * 256 +
ord($bytes{$offset+3}));
}
/**
* Extract a signed long from bytes.
*
* @param string the bytes.
*
* @param int the offset. The long found at offset will be returned
* as an integer. There must be at least four bytes available
* beginning at the offset given.
*
* @return int the signed long found at offset, e.g., an integer in
* the range -2147483648 to 2147483647.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*/
static function bytesToSLong($bytes, $offset, $endian) {
$n = self::bytesToLong($bytes, $offset, $endian);
if ($n > 2147483647)
return $n - 4294967296;
else
return $n;
}
/**
* Extract an unsigned rational from bytes.
*
* @param string the bytes.
*
* @param int the offset. The rational found at offset will be
* returned as an array. There must be at least eight bytes
* available beginning at the offset given.
*
* @return array the unsigned rational found at offset, e.g., an
* array with two integers in the range 0 to 4294967295.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*/
static function bytesToRational($bytes, $offset, $endian) {
return array(self::bytesToLong($bytes, $offset, $endian),
self::bytesToLong($bytes, $offset+4, $endian));
}
/**
* Extract a signed rational from bytes.
*
* @param string the bytes.
*
* @param int the offset. The rational found at offset will be
* returned as an array. There must be at least eight bytes
* available beginning at the offset given.
*
* @return array the signed rational found at offset, e.g., an array
* with two integers in the range -2147483648 to 2147483647.
*
* @param PelByteOrder one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
*/
static function bytesToSRational($bytes, $offset, $endian) {
return array(self::bytesToSLong($bytes, $offset, $endian),
self::bytesToSLong($bytes, $offset+4, $endian));
}
/**
* Format bytes for dumping.
*
* This method is for debug output, it will format a string as a
* hexadecimal dump suitable for display on a terminal. The output
* is printed directly to standard out.
*
* @param string the bytes that will be dumped.
*
* @param int the maximum number of bytes to dump. If this is left
* out (or left to the default of 0), then the entire string will be
* dumped.
*/
static function bytesToDump($bytes, $max = 0) {
$s = strlen($bytes);
if ($max > 0)
$s = min($max, $s);
$line = 24;
for ($i = 0; $i < $s; $i++) {
printf('%02X ', ord($bytes{$i}));
if (($i+1) % $line == 0)
print("\n");
}
print("\n");
}
}
?>

View File

@ -0,0 +1,525 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelDataWindow.php 387 2005-10-05 11:02:52Z mgeisler $ */
/**
* A container for bytes with a limited window of accessible bytes.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 387 $
* @date $Date: 2005-10-05 13:02:52 +0200 (Wed, 05 Oct 2005) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelException.php');
require_once('PelConvert.php');
/**#@-*/
/**
* An exception thrown when an invalid offset is encountered.
*
* @package PEL
* @subpackage Exception
*/
class PelDataWindowOffsetException extends PelException {}
/**
* An exception thrown when an invalid window is encountered.
*
* @package PEL
* @subpackage Exception
*/
class PelDataWindowWindowException extends PelException {}
/**
* The window.
*
* @package PEL
*/
class PelDataWindow {
/**
* The data held by this window.
*
* The string can contain any kind of data, including binary data.
*
* @var string
*/
private $data = '';
/**
* The byte order currently in use.
*
* This will be the byte order used when data is read using the for
* example the {@link getShort} function. It must be one of {@link
* PelConvert::LITTLE_ENDIAN} and {@link PelConvert::BIG_ENDIAN}.
*
* @var PelByteOrder
* @see setByteOrder, getByteOrder
*/
private $order;
/**
* The start of the current window.
*
* All offsets used for access into the data will count from this
* offset, effectively limiting access to a window starting at this
* byte.
*
* @var int
* @see setWindowStart
*/
private $start = 0;
/**
* The size of the current window.
*
* All offsets used for access into the data will be limited by this
* variable. A valid offset must be strictly less than this
* variable.
*
* @var int
* @see setWindowSize
*/
private $size = 0;
/**
* Construct a new data window with the data supplied.
*
* @param string the data that this window will contain. The data
* will be copied into the new data window.
*
* @param boolean the initial byte order of the window. This must
* be either {@link PelConvert::LITTLE_ENDIAN} or {@link
* PelConvert::BIG_ENDIAN}. This will be used when integers are
* read from the data, and it can be changed later with {@link
* setByteOrder()}.
*/
function __construct($d = '', $e = PelConvert::LITTLE_ENDIAN) {
$this->data = $d;
$this->order = $e;
$this->size = strlen($d);
}
/**
* Get the size of the data window.
*
* @return int the number of bytes covered by the window. The
* allowed offsets go from 0 up to this number minus one.
*
* @see getBytes()
*/
function getSize() {
return $this->size;
}
/**
* Change the byte order of the data.
*
* @param PelByteOrder the new byte order. This must be either
* {@link PelConvert::LITTLE_ENDIAN} or {@link
* PelConvert::BIG_ENDIAN}.
*/
function setByteOrder($o) {
$this->order = $o;
}
/**
* Get the currently used byte order.
*
* @return PelByteOrder this will be either {@link
* PelConvert::LITTLE_ENDIAN} or {@link PelConvert::BIG_ENDIAN}.
*/
function getByteOrder() {
return $this->order;
}
/* Move the start of the window forward.
*
* @param int the new start of the window. All new offsets will be
* calculated from this new start offset, and the size of the window
* will shrink to keep the end of the window in place.
*/
function setWindowStart($start) {
if ($start < 0 || $start > $this->size)
throw new PelDataWindowWindowException('Window [%d, %d] does ' .
'not fit in window [0, %d]',
$start, $this->size, $this->size);
$this->start += $start;
$this->size -= $start;
}
/**
* Adjust the size of the window.
*
* The size can only be made smaller.
*
* @param int the desired size of the window. If the argument is
* negative, the window will be shrunk by the argument.
*/
function setWindowSize($size) {
if ($size < 0)
$size += $this->size;
if ($size < 0 || $size > $this->size)
throw new PelDataWindowWindowException('Window [0, %d] ' .
'does not fit in window [0, %d]',
$size, $this->size);
$this->size = $size;
}
/**
* Make a new data window with the same data as the this window.
*
* @param mixed if an integer is supplied, then it will be the start
* of the window in the clone. If left unspecified, then the clone
* will inherit the start from this object.
*
* @param mixed if an integer is supplied, then it will be the size
* of the window in the clone. If left unspecified, then the clone
* will inherit the size from this object.
*
* @return PelDataWindow a new window that operates on the same data
* as this window, but (optionally) with a smaller window size.
*/
function getClone($start = false, $size = false) {
$c = clone $this;
if (is_int($start))
$c->setWindowStart($start);
if (is_int($size))
$c->setWindowSize($size);
return $c;
}
/**
* Validate an offset against the current window.
*
* @param int the offset to be validated. If the offset is negative
* or if it is greater than or equal to the current window size,
* then a {@link PelDataWindowOffsetException} is thrown.
*
* @return void if the offset is valid nothing is returned, if it is
* invalid a new {@link PelDataWindowOffsetException} is thrown.
*/
private function validateOffset($o) {
if ($o < 0 || $o >= $this->size)
throw new PelDataWindowOffsetException('Offset %d not within [%d, %d]',
$o, 0, $this->size-1);
}
/**
* Return some or all bytes visible in the window.
*
* This method works just like the standard {@link substr()}
* function in PHP with the exception that it works within the
* window of accessible bytes and does strict range checking.
*
* @param int the offset to the first byte returned. If a negative
* number is given, then the counting will be from the end of the
* window. Invalid offsets will result in a {@link
* PelDataWindowOffsetException} being thrown.
*
* @param int the size of the sub-window. If a negative number is
* given, then that many bytes will be omitted from the result.
*
* @return string a subset of the bytes in the window. This will
* always return no more than {@link getSize()} bytes.
*/
function getBytes($start = false, $size = false) {
if (is_int($start)) {
if ($start < 0)
$start += $this->size;
$this->validateOffset($start);
} else {
$start = 0;
}
if (is_int($size)) {
if ($size <= 0)
$size += $this->size - $start;
$this->validateOffset($start+$size);
} else {
$size = $this->size - $start;
}
return substr($this->data, $this->start + $start, $size);
}
/**
* Return an unsigned byte from the data.
*
* @param int the offset into the data. An offset of zero will
* return the first byte in the current allowed window. The last
* valid offset is equal to {@link getSize()}-1. Invalid offsets
* will result in a {@link PelDataWindowOffsetException} being
* thrown.
*
* @return int the unsigned byte found at offset.
*/
function getByte($o = 0) {
/* Validate the offset --- this throws an exception if offset is
* out of range. */
$this->validateOffset($o);
/* Translate the offset into an offset into the data. */
$o += $this->start;
/* Return an unsigned byte. */
return PelConvert::bytesToByte($this->data, $o);
}
/**
* Return a signed byte from the data.
*
* @param int the offset into the data. An offset of zero will
* return the first byte in the current allowed window. The last
* valid offset is equal to {@link getSize()}-1. Invalid offsets
* will result in a {@link PelDataWindowOffsetException} being
* thrown.
*
* @return int the signed byte found at offset.
*/
function getSByte($o = 0) {
/* Validate the offset --- this throws an exception if offset is
* out of range. */
$this->validateOffset($o);
/* Translate the offset into an offset into the data. */
$o += $this->start;
/* Return a signed byte. */
return PelConvert::bytesToSByte($this->data, $o);
}
/**
* Return an unsigned short read from the data.
*
* @param int the offset into the data. An offset of zero will
* return the first short available in the current allowed window.
* The last valid offset is equal to {@link getSize()}-2. Invalid
* offsets will result in a {@link PelDataWindowOffsetException}
* being thrown.
*
* @return int the unsigned short found at offset.
*/
function getShort($o = 0) {
/* Validate the offset+1 to see if we can safely get two bytes ---
* this throws an exception if offset is out of range. */
$this->validateOffset($o);
$this->validateOffset($o+1);
/* Translate the offset into an offset into the data. */
$o += $this->start;
/* Return an unsigned short. */
return PelConvert::bytesToShort($this->data, $o, $this->order);
}
/**
* Return a signed short read from the data.
*
* @param int the offset into the data. An offset of zero will
* return the first short available in the current allowed window.
* The last valid offset is equal to {@link getSize()}-2. Invalid
* offsets will result in a {@link PelDataWindowOffsetException}
* being thrown.
*
* @return int the signed short found at offset.
*/
function getSShort($o = 0) {
/* Validate the offset+1 to see if we can safely get two bytes ---
* this throws an exception if offset is out of range. */
$this->validateOffset($o);
$this->validateOffset($o+1);
/* Translate the offset into an offset into the data. */
$o += $this->start;
/* Return a signed short. */
return PelConvert::bytesToSShort($this->data, $o, $this->order);
}
/**
* Return an unsigned long read from the data.
*
* @param int the offset into the data. An offset of zero will
* return the first long available in the current allowed window.
* The last valid offset is equal to {@link getSize()}-4. Invalid
* offsets will result in a {@link PelDataWindowOffsetException}
* being thrown.
*
* @return int the unsigned long found at offset.
*/
function getLong($o = 0) {
/* Validate the offset+3 to see if we can safely get four bytes
* --- this throws an exception if offset is out of range. */
$this->validateOffset($o);
$this->validateOffset($o+3);
/* Translate the offset into an offset into the data. */
$o += $this->start;
/* Return an unsigned long. */
return PelConvert::bytesToLong($this->data, $o, $this->order);
}
/**
* Return a signed long read from the data.
*
* @param int the offset into the data. An offset of zero will
* return the first long available in the current allowed window.
* The last valid offset is equal to {@link getSize()}-4. Invalid
* offsets will result in a {@link PelDataWindowOffsetException}
* being thrown.
*
* @return int the signed long found at offset.
*/
function getSLong($o = 0) {
/* Validate the offset+3 to see if we can safely get four bytes
* --- this throws an exception if offset is out of range. */
$this->validateOffset($o);
$this->validateOffset($o+3);
/* Translate the offset into an offset into the data. */
$o += $this->start;
/* Return a signed long. */
return PelConvert::bytesToSLong($this->data, $o, $this->order);
}
/**
* Return an unsigned rational read from the data.
*
* @param int the offset into the data. An offset of zero will
* return the first rational available in the current allowed
* window. The last valid offset is equal to {@link getSize()}-8.
* Invalid offsets will result in a {@link
* PelDataWindowOffsetException} being thrown.
*
* @return array the unsigned rational found at offset. A rational
* number is represented as an array of two numbers: the enumerator
* and denominator. Both of these numbers will be unsigned longs.
*/
function getRational($o = 0) {
return array($this->getLong($o), $this->getLong($o+4));
}
/**
* Return a signed rational read from the data.
*
* @param int the offset into the data. An offset of zero will
* return the first rational available in the current allowed
* window. The last valid offset is equal to {@link getSize()}-8.
* Invalid offsets will result in a {@link
* PelDataWindowOffsetException} being thrown.
*
* @return array the signed rational found at offset. A rational
* number is represented as an array of two numbers: the enumerator
* and denominator. Both of these numbers will be signed longs.
*/
function getSRational($o = 0) {
return array($this->getSLong($o), $this->getSLong($o+4));
}
/**
* String comparison on substrings.
*
* @param int the offset into the data. An offset of zero will make
* the comparison start with the very first byte available in the
* window. The last valid offset is equal to {@link getSize()}
* minus the length of the string. If the string is too long, then
* a {@link PelDataWindowOffsetException} will be thrown.
*
* @param string the string to compare with.
*
* @return boolean true if the string given matches the data in the
* window, at the specified offset, false otherwise. The comparison
* will stop as soon as a mismatch if found.
*/
function strcmp($o, $str) {
/* Validate the offset of the final character we might have to
* check. */
$s = strlen($str);
$this->validateOffset($o);
$this->validateOffset($o + $s - 1);
/* Translate the offset into an offset into the data. */
$o += $this->start;
/* Check each character, return as soon as the answer is known. */
for ($i = 0; $i < $s; $i++) {
if ($this->data{$o + $i} != $str{$i})
return false;
}
/* All characters matches each other, return true. */
return true;
}
/**
* Return a string representation of the data window.
*
* @return string a description of the window with information about
* the number of bytes accessible, the total number of bytes, and
* the window start and stop.
*/
function __toString() {
return Pel::fmt('DataWindow: %d bytes in [%d, %d] of %d bytes',
$this->size,
$this->start, $this->start + $this->size,
strlen($this->data));
}
}
?>

View File

@ -0,0 +1,382 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelEntry.php 442 2006-09-17 12:45:10Z mgeisler $ */
/**
* Classes for dealing with Exif entries.
*
* This file defines two exception classes and the abstract class
* {@link PelEntry} which provides the basic methods that all Exif
* entries will have. All Exif entries will be represented by
* descendants of the {@link PelEntry} class --- the class itself is
* abstract and so it cannot be instantiated.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 442 $
* @date $Date: 2006-09-17 14:45:10 +0200 (Sun, 17 Sep 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelException.php');
require_once('PelFormat.php');
require_once('PelTag.php');
require_once('Pel.php');
/**#@-*/
/**
* Exception indicating a problem with an entry.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
class PelEntryException extends PelException {
/**
* The IFD type (if known).
*
* @var int
*/
protected $type;
/**
* The tag of the entry (if known).
*
* @var PelTag
*/
protected $tag;
/**
* Get the IFD type associated with the exception.
*
* @return int one of {@link PelIfd::IFD0}, {@link PelIfd::IFD1},
* {@link PelIfd::EXIF}, {@link PelIfd::GPS}, or {@link
* PelIfd::INTEROPERABILITY}. If no type is set, null is returned.
*/
function getIfdType() {
return $this->type;
}
/**
* Get the tag associated with the exception.
*
* @return PelTag the tag. If no tag is set, null is returned.
*/
function getTag() {
return $this->tag;
}
}
/**
* Exception indicating that an unexpected format was found.
*
* The documentation for each tag in {@link PelTag} will detail any
* constrains.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
class PelUnexpectedFormatException extends PelEntryException {
/**
* Construct a new exception indicating an invalid format.
*
* @param int the type of IFD.
*
* @param PelTag the tag for which the violation was found.
*
* @param PelFormat the format found.
*
* @param PelFormat the expected format.
*/
function __construct($type, $tag, $found, $expected) {
parent::__construct('Unexpected format found for %s tag: PelFormat::%s. ' .
'Expected PelFormat::%s instead.',
PelTag::getName($type, $tag),
strtoupper(PelFormat::getName($found)),
strtoupper(PelFormat::getName($expected)));
$this->tag = $tag;
$this->type = $type;
}
}
/**
* Exception indicating that an unexpected number of components was
* found.
*
* Some tags have strict limits as to the allowed number of
* components, and this exception is thrown if the data violates such
* a constraint. The documentation for each tag in {@link PelTag}
* explains the expected number of components.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
class PelWrongComponentCountException extends PelEntryException {
/**
* Construct a new exception indicating a wrong number of
* components.
*
* @param int the type of IFD.
*
* @param PelTag the tag for which the violation was found.
*
* @param int the number of components found.
*
* @param int the expected number of components.
*/
function __construct($type, $tag, $found, $expected) {
parent::__construct('Wrong number of components found for %s tag: %d. ' .
'Expected %d.',
PelTag::getName($type, $tag), $found, $expected);
$this->tag = $tag;
$this->type = $type;
}
}
/**
* Common ancestor class of all {@link PelIfd} entries.
*
* As this class is abstract you cannot instantiate objects from it.
* It only serves as a common ancestor to define the methods common to
* all entries. The most important methods are {@link getValue()} and
* {@link setValue()}, both of which is abstract in this class. The
* descendants will give concrete implementations for them.
*
* If you have some data coming from an image (some raw bytes), then
* the static method {@link newFromData()} is helpful --- it will look
* at the data and give you a proper decendent of {@link PelEntry}
* back.
*
* If you instead want to have an entry for some data which take the
* form of an integer, a string, a byte, or some other PHP type, then
* don't use this class. You should instead create an object of the
* right subclass ({@link PelEntryShort} for short integers, {@link
* PelEntryAscii} for strings, and so on) directly.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
abstract class PelEntry {
/**
* Type of IFD containing this tag.
*
* This must be one of the constants defined in {@link PelIfd}:
* {@link PelIfd::IFD0} for the main image IFD, {@link PelIfd::IFD1}
* for the thumbnail image IFD, {@link PelIfd::EXIF} for the Exif
* sub-IFD, {@link PelIfd::GPS} for the GPS sub-IFD, or {@link
* PelIfd::INTEROPERABILITY} for the interoperability sub-IFD.
*
* @var int
*/
protected $ifd_type;
/**
* The bytes representing this entry.
*
* Subclasses must either override {@link getBytes()} or, if
* possible, maintain this property so that it always contains a
* true representation of the entry.
*
* @var string
*/
protected $bytes = '';
/**
* The {@link PelTag} of this entry.
*
* @var PelTag
*/
protected $tag;
/**
* The {@link PelFormat} of this entry.
*
* @var PelFormat
*/
protected $format;
/**
* The number of components of this entry.
*
* @var int
*/
protected $components;
/**
* Return the tag of this entry.
*
* @return PelTag the tag of this entry.
*/
function getTag() {
return $this->tag;
}
/**
* Return the type of IFD which holds this entry.
*
* @return int one of the constants defined in {@link PelIfd}:
* {@link PelIfd::IFD0} for the main image IFD, {@link PelIfd::IFD1}
* for the thumbnail image IFD, {@link PelIfd::EXIF} for the Exif
* sub-IFD, {@link PelIfd::GPS} for the GPS sub-IFD, or {@link
* PelIfd::INTEROPERABILITY} for the interoperability sub-IFD.
*/
function getIfdType() {
return $this->ifd_type;
}
/**
* Update the IFD type.
*
* @param int must be one of the constants defined in {@link
* PelIfd}: {@link PelIfd::IFD0} for the main image IFD, {@link
* PelIfd::IFD1} for the thumbnail image IFD, {@link PelIfd::EXIF}
* for the Exif sub-IFD, {@link PelIfd::GPS} for the GPS sub-IFD, or
* {@link PelIfd::INTEROPERABILITY} for the interoperability
* sub-IFD.
*/
function setIfdType($type) {
$this->ifd_type = $type;
}
/**
* Return the format of this entry.
*
* @return PelFormat the format of this entry.
*/
function getFormat() {
return $this->format;
}
/**
* Return the number of components of this entry.
*
* @return int the number of components of this entry.
*/
function getComponents() {
return $this->components;
}
/**
* Turn this entry into bytes.
*
* @param PelByteOrder the desired byte order, which must be either
* {@link Convert::LITTLE_ENDIAN} or {@link Convert::BIG_ENDIAN}.
*
* @return string bytes representing this entry.
*/
function getBytes($o) {
return $this->bytes;
}
/**
* Get the value of this entry as text.
*
* The value will be returned in a format suitable for presentation,
* e.g., rationals will be returned as 'x/y', ASCII strings will be
* returned as themselves etc.
*
* @param boolean some values can be returned in a long or more
* brief form, and this parameter controls that.
*
* @return string the value as text.
*/
abstract function getText($brief = false);
/**
* Get the value of this entry.
*
* The value returned will generally be the same as the one supplied
* to the constructor or with {@link setValue()}. For a formatted
* version of the value, one should use {@link getText()} instead.
*
* @return mixed the unformatted value.
*/
abstract function getValue();
/**
* Set the value of this entry.
*
* The value should be in the same format as for the constructor.
*
* @param mixed the new value.
*
* @abstract
*/
function setValue($value) {
/* This (fake) abstract method is here to make it possible for the
* documentation to refer to PelEntry::setValue().
*
* It cannot declared abstract in the proper PHP way, for then PHP
* wont allow subclasses to define it with two arguments (which is
* what PelEntryCopyright does).
*/
throw new PelException('setValue() is abstract.');
}
/**
* Turn this entry into a string.
*
* @return string a string representation of this entry. This is
* mostly for debugging.
*/
function __toString() {
$str = Pel::fmt(" Tag: 0x%04X (%s)\n",
$this->tag, PelTag::getName($this->ifd_type, $this->tag));
$str .= Pel::fmt(" Format : %d (%s)\n",
$this->format, PelFormat::getName($this->format));
$str .= Pel::fmt(" Components: %d\n", $this->components);
if ($this->getTag() != PelTag::MAKER_NOTE &&
$this->getTag() != PelTag::PRINT_IM)
$str .= Pel::fmt(" Value : %s\n", print_r($this->getValue(), true));
$str .= Pel::fmt(" Text : %s\n", $this->getText());
return $str;
}
}
?>

View File

@ -0,0 +1,482 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelEntryAscii.php 443 2006-09-17 18:32:04Z mgeisler $ */
/**
* Classes used to hold ASCII strings.
*
* The classes defined here are to be used for Exif entries holding
* ASCII strings, such as {@link PelTag::MAKE}, {@link
* PelTag::SOFTWARE}, and {@link PelTag::DATE_TIME}. For
* entries holding normal textual ASCII strings the class {@link
* PelEntryAscii} should be used, but for entries holding
* timestamps the class {@link PelEntryTime} would be more
* convenient instead. Copyright information is handled by the {@link
* PelEntryCopyright} class.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 443 $
* @date $Date: 2006-09-17 20:32:04 +0200 (Sun, 17 Sep 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelEntry.php');
/**#@-*/
/**
* Class for holding a plain ASCII string.
*
* This class can hold a single ASCII string, and it will be used as in
* <code>
* $entry = $ifd->getEntry(PelTag::IMAGE_DESCRIPTION);
* print($entry->getValue());
* $entry->setValue('This is my image. I like it.');
* </code>
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryAscii extends PelEntry {
/**
* The string hold by this entry.
*
* This is the string that was given to the {@link __construct
* constructor} or later to {@link setValue}, without any final NULL
* character.
*
* @var string
*/
private $str;
/**
* Make a new PelEntry that can hold an ASCII string.
*
* @param int the tag which this entry represents. This should be
* one of the constants defined in {@link PelTag}, e.g., {@link
* PelTag::IMAGE_DESCRIPTION}, {@link PelTag::MODEL}, or any other
* tag with format {@link PelFormat::ASCII}.
*
* @param string the string that this entry will represent. The
* string must obey the same rules as the string argument to {@link
* setValue}, namely that it should be given without any trailing
* NULL character and that it must be plain 7-bit ASCII.
*/
function __construct($tag, $str = '') {
$this->tag = $tag;
$this->format = PelFormat::ASCII;
$this->setValue($str);
}
/**
* Give the entry a new ASCII value.
*
* This will overwrite the previous value. The value can be
* retrieved later with the {@link getValue} method.
*
* @param string the new value of the entry. This should be given
* without any trailing NULL character. The string must be plain
* 7-bit ASCII, the string should contain no high bytes.
*
* @todo Implement check for high bytes?
*/
function setValue($str) {
$this->components = strlen($str)+1;
$this->str = $str;
$this->bytes = $str . chr(0x00);
}
/**
* Return the ASCII string of the entry.
*
* @return string the string held, without any final NULL character.
* The string will be the same as the one given to {@link setValue}
* or to the {@link __construct constructor}.
*/
function getValue() {
return $this->str;
}
/**
* Return the ASCII string of the entry.
*
* This methods returns the same as {@link getValue}.
*
* @param boolean not used with ASCII entries.
*
* @return string the string held, without any final NULL character.
* The string will be the same as the one given to {@link setValue}
* or to the {@link __construct constructor}.
*/
function getText($brief = false) {
return $this->str;
}
}
/**
* Class for holding a date and time.
*
* This class can hold a timestamp, and it will be used as
* in this example where the time is advanced by one week:
* <code>
* $entry = $ifd->getEntry(PelTag::DATE_TIME_ORIGINAL);
* $time = $entry->getValue();
* print('The image was taken on the ' . date($time, 'jS'));
* $entry->setValue($time + 7 * 24 * 3600);
* </code>
*
* The example used a standard UNIX timestamp, which is the default
* for this class.
*
* But the Exif format defines dates outside the range of a UNIX
* timestamp (about 1970 to 2038) and so you can also get access to
* the timestamp in two other formats: a simple string or a Julian Day
* Count. Please see the Calendar extension in the PHP Manual for more
* information about the Julian Day Count.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryTime extends PelEntryAscii {
/**
* Constant denoting a UNIX timestamp.
*/
const UNIX_TIMESTAMP = 1;
/**
* Constant denoting a Exif string.
*/
const EXIF_STRING = 2;
/**
* Constant denoting a Julian Day Count.
*/
const JULIAN_DAY_COUNT = 3;
/**
* The Julian Day Count of the timestamp held by this entry.
*
* This is an integer counting the number of whole days since
* January 1st, 4713 B.C. The fractional part of the timestamp held
* by this entry is stored in {@link $seconds}.
*
* @var int
*/
private $day_count;
/**
* The number of seconds into the day of the timestamp held by this
* entry.
*
* The number of whole days is stored in {@link $day_count} and the
* number of seconds left-over is stored here.
*
* @var int
*/
private $seconds;
/**
* Make a new entry for holding a timestamp.
*
* @param int the Exif tag which this entry represents. There are
* only three standard tags which hold timestamp, so this should be
* one of the constants {@link PelTag::DATE_TIME}, {@link
* PelTag::DATE_TIME_ORIGINAL}, or {@link
* PelTag::DATE_TIME_DIGITIZED}.
*
* @param int the timestamp held by this entry in the correct form
* as indicated by the third argument. For {@link UNIX_TIMESTAMP}
* this is an integer counting the number of seconds since January
* 1st 1970, for {@link EXIF_STRING} this is a string of the form
* 'YYYY:MM:DD hh:mm:ss', and for {@link JULIAN_DAY_COUNT} this is a
* floating point number where the integer part denotes the day
* count and the fractional part denotes the time of day (0.25 means
* 6:00, 0.75 means 18:00).
*
* @param int the type of the timestamp. This must be one of
* {@link UNIX_TIMESTAMP}, {@link EXIF_STRING}, or
* {@link JULIAN_DAY_COUNT}.
*/
function __construct($tag, $timestamp, $type = self::UNIX_TIMESTAMP) {
parent::__construct($tag);
$this->setValue($timestamp, $type);
}
/**
* Return the timestamp of the entry.
*
* The timestamp held by this entry is returned in one of three
* formats: as a standard UNIX timestamp (default), as a fractional
* Julian Day Count, or as a string.
*
* @param int the type of the timestamp. This must be one of
* {@link UNIX_TIMESTAMP}, {@link EXIF_STRING}, or
* {@link JULIAN_DAY_COUNT}.
*
* @return int the timestamp held by this entry in the correct form
* as indicated by the type argument. For {@link UNIX_TIMESTAMP}
* this is an integer counting the number of seconds since January
* 1st 1970, for {@link EXIF_STRING} this is a string of the form
* 'YYYY:MM:DD hh:mm:ss', and for {@link JULIAN_DAY_COUNT} this is a
* floating point number where the integer part denotes the day
* count and the fractional part denotes the time of day (0.25 means
* 6:00, 0.75 means 18:00).
*/
function getValue($type = self::UNIX_TIMESTAMP) {
switch ($type) {
case self::UNIX_TIMESTAMP:
$seconds = jdtounix($this->day_count);
if ($seconds === false)
/* jdtounix() return false if the Julian Day Count is outside
* the range of a UNIX timestamp. */
return false;
else
return $seconds + $this->seconds;
case self::EXIF_STRING:
list($month, $day, $year) = explode('/', jdtogregorian($this->day_count));
$hours = (int)($this->seconds / 3600);
$minutes = (int)($this->seconds % 3600 / 60);
$seconds = $this->seconds % 60;
return sprintf('%04d:%02d:%02d %02d:%02d:%02d',
$year, $month, $day, $hours, $minutes, $seconds);
case self::JULIAN_DAY_COUNT:
return $this->day_count + $this->seconds / 86400;
default:
throw new PelInvalidArgumentException('Expected UNIX_TIMESTAMP (%d), ' .
'EXIF_STRING (%d), or ' .
'JULIAN_DAY_COUNT (%d) for $type, '.
'got %d.',
self::UNIX_TIMESTAMP,
self::EXIF_STRING,
self::JULIAN_DAY_COUNT,
$type);
}
}
/**
* Update the timestamp held by this entry.
*
* @param int the timestamp held by this entry in the correct form
* as indicated by the third argument. For {@link UNIX_TIMESTAMP}
* this is an integer counting the number of seconds since January
* 1st 1970, for {@link EXIF_STRING} this is a string of the form
* 'YYYY:MM:DD hh:mm:ss', and for {@link JULIAN_DAY_COUNT} this is a
* floating point number where the integer part denotes the day
* count and the fractional part denotes the time of day (0.25 means
* 6:00, 0.75 means 18:00).
*
* @param int the type of the timestamp. This must be one of
* {@link UNIX_TIMESTAMP}, {@link EXIF_STRING}, or
* {@link JULIAN_DAY_COUNT}.
*
* @todo How to deal with timezones? Use the TimeZoneOffset tag
* 0x882A?
*/
function setValue($timestamp, $type = self::UNIX_TIMESTAMP) {
switch ($type) {
case self::UNIX_TIMESTAMP:
$this->day_count = unixtojd($timestamp);
$this->seconds = $timestamp % 86400;
break;
case self::EXIF_STRING:
/* Clean the timestamp: some timestamps are broken other
* separators than ':' and ' '. */
$d = split('[^0-9]+', $timestamp);
$this->day_count = gregoriantojd($d[1], $d[2], $d[0]);
$this->seconds = $d[3]*3600 + $d[4]*60 + $d[5];
break;
case self::JULIAN_DAY_COUNT:
$this->day_count = (int)floor($timestamp);
$this->seconds = (int)(86400 * ($timestamp - floor($timestamp)));
break;
default:
throw new PelInvalidArgumentException('Expected UNIX_TIMESTAMP (%d), ' .
'EXIF_STRING (%d), or ' .
'JULIAN_DAY_COUNT (%d) for $type, '.
'got %d.',
self::UNIX_TIMESTAMP,
self::EXIF_STRING,
self::JULIAN_DAY_COUNT,
$type);
}
/* Now finally update the string which will be used when this is
* turned into bytes. */
parent::setValue($this->getValue(self::EXIF_STRING));
}
}
/**
* Class for holding copyright information.
*
* The Exif standard specifies a certain format for copyright
* information where the one {@link PelTag::COPYRIGHT copyright
* tag} holds both the photographer and editor copyrights, separated
* by a NULL character.
*
* This class is used to manipulate that tag so that the format is
* kept to the standard. A common use would be to add a new copyright
* tag to an image, since most cameras do not add this tag themselves.
* This would be done like this:
*
* <code>
* $entry = new PelEntryCopyright('Copyright, Martin Geisler, 2004');
* $ifd0->addEntry($entry);
* </code>
*
* Here we only set the photographer copyright, use the optional
* second argument to specify the editor copyright. If there is only
* an editor copyright, then let the first argument be the empty
* string.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryCopyright extends PelEntryAscii {
/**
* The photographer copyright.
*
* @var string
*/
private $photographer;
/**
* The editor copyright.
*
* @var string
*/
private $editor;
/**
* Make a new entry for holding copyright information.
*
* @param string the photographer copyright. Use the empty string
* if there is no photographer copyright.
*
* @param string the editor copyright. Use the empty string if
* there is no editor copyright.
*/
function __construct($photographer = '', $editor = '') {
parent::__construct(PelTag::COPYRIGHT);
$this->setValue($photographer, $editor);
}
/**
* Update the copyright information.
*
* @param string the photographer copyright. Use the empty string
* if there is no photographer copyright.
*
* @param string the editor copyright. Use the empty string if
* there is no editor copyright.
*/
function setValue($photographer = '', $editor = '') {
$this->photographer = $photographer;
$this->editor = $editor;
if ($photographer == '' && $editor != '')
$photographer = ' ';
if ($editor == '')
parent::setValue($photographer);
else
parent::setValue($photographer . chr(0x00) . $editor);
}
/**
* Retrive the copyright information.
*
* The strings returned will be the same as the one used previously
* with either {@link __construct the constructor} or with {@link
* setValue}.
*
* @return array an array with two strings, the photographer and
* editor copyrights. The two fields will be returned in that
* order, so that the first array index will be the photographer
* copyright, and the second will be the editor copyright.
*/
function getValue() {
return array($this->photographer, $this->editor);
}
/**
* Return a text string with the copyright information.
*
* The photographer and editor copyright fields will be returned
* with a '-' in between if both copyright fields are present,
* otherwise only one of them will be returned.
*
* @param boolean if false, then the strings '(Photographer)' and
* '(Editor)' will be appended to the photographer and editor
* copyright fields (if present), otherwise the fields will be
* returned as is.
*
* @return string the copyright information in a string.
*/
function getText($brief = false) {
if ($brief) {
$p = '';
$e = '';
} else {
$p = ' ' . Pel::tra('(Photographer)');
$e = ' ' . Pel::tra('(Editor)');
}
if ($this->photographer != '' && $this->editor != '')
return $this->photographer . $p . ' - ' . $this->editor . $e;
if ($this->photographer != '')
return $this->photographer . $p;
if ($this->editor != '')
return $this->editor . $e;
return '';
}
}
?>

View File

@ -0,0 +1,275 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelEntryByte.php 419 2006-02-20 16:22:36Z mgeisler $ */
/**
* Classes used to hold bytes, both signed and unsigned. The {@link
* PelEntryWindowsString} class is used to manipulate strings in the
* format Windows XP needs.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 419 $
* @date $Date: 2006-02-20 17:22:36 +0100 (Mon, 20 Feb 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelEntryNumber.php');
/**#@-*/
/**
* Class for holding unsigned bytes.
*
* This class can hold bytes, either just a single byte or an array of
* bytes. The class will be used to manipulate any of the Exif tags
* which has format {@link PelFormat::BYTE}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryByte extends PelEntryNumber {
/**
* Make a new entry that can hold an unsigned byte.
*
* The method accept several integer arguments. The {@link
* getValue} method will always return an array except for when a
* single integer argument is given here.
*
* @param PelTag the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag}
* which has format {@link PelFormat::BYTE}.
*
* @param int $value... the byte(s) that this entry will represent.
* The argument passed must obey the same rules as the argument to
* {@link setValue}, namely that it should be within range of an
* unsigned byte, that is between 0 and 255 (inclusive). If not,
* then a {@link PelOverflowException} will be thrown.
*/
function __construct($tag /* $value... */) {
$this->tag = $tag;
$this->min = 0;
$this->max = 255;
$this->format = PelFormat::BYTE;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int the number that should be converted.
*
* @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
*
* @return string bytes representing the number given.
*/
function numberToBytes($number, $order) {
return chr($number);
}
}
/**
* Class for holding signed bytes.
*
* This class can hold bytes, either just a single byte or an array of
* bytes. The class will be used to manipulate any of the Exif tags
* which has format {@link PelFormat::BYTE}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntrySByte extends PelEntryNumber {
/**
* Make a new entry that can hold a signed byte.
*
* The method accept several integer arguments. The {@link getValue}
* method will always return an array except for when a single
* integer argument is given here.
*
* @param PelTag the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag}
* which has format {@link PelFormat::BYTE}.
*
* @param int $value... the byte(s) that this entry will represent.
* The argument passed must obey the same rules as the argument to
* {@link setValue}, namely that it should be within range of a
* signed byte, that is between -128 and 127 (inclusive). If not,
* then a {@link PelOverflowException} will be thrown.
*/
function __construct($tag /* $value... */) {
$this->tag = $tag;
$this->min = -128;
$this->max = 127;
$this->format = PelFormat::SBYTE;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int the number that should be converted.
*
* @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
*
* @return string bytes representing the number given.
*/
function numberToBytes($number, $order) {
return chr($number);
}
}
/**
* Class used to manipulate strings in the format Windows XP uses.
*
* When examining the file properties of an image in Windows XP one
* can fill in title, comment, author, keyword, and subject fields.
* Filling those fields and pressing OK will result in the data being
* written into the Exif data in the image.
*
* The data is written in a non-standard format and can thus not be
* loaded directly --- this class is needed to translate it into
* normal strings.
*
* It is important that entries from this class are only created with
* the {@link PelTag::XP_TITLE}, {@link PelTag::XP_COMMENT}, {@link
* PelTag::XP_AUTHOR}, {@link PelTag::XP_KEYWORD}, and {@link
* PelTag::XP_SUBJECT} tags. If another tag is used the data will no
* longer be correctly decoded when reloaded with PEL. (The data will
* be loaded as an {@link PelEntryByte} entry, which isn't as useful.)
*
* This class is to be used as in
* <code>
* $entry = $ifd->getEntry(PelTag::XP_TITLE);
* print($entry->getValue());
* $entry->setValue('My favorite cat');
* </code>
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryWindowsString extends PelEntry {
/**
* The string hold by this entry.
*
* This is the string that was given to the {@link __construct
* constructor} or later to {@link setValue}, without any extra NULL
* characters or any such nonsense.
*
* @var string
*/
private $str;
/**
* Make a new PelEntry that can hold a Windows XP specific string.
*
* @param int the tag which this entry represents. This should be
* one of {@link PelTag::XP_TITLE}, {@link PelTag::XP_COMMENT},
* {@link PelTag::XP_AUTHOR}, {@link PelTag::XP_KEYWORD}, and {@link
* PelTag::XP_SUBJECT} tags. If another tag is used, then this
* entry will be incorrectly reloaded as a {@link PelEntryByte}.
*
* @param string the string that this entry will represent. It will
* be passed to {@link setValue} and thus has to obey its
* requirements.
*/
function __construct($tag, $str = '') {
$this->tag = $tag;
$this->format = PelFormat::BYTE;
$this->setValue($str);
}
/**
* Give the entry a new value.
*
* This will overwrite the previous value. The value can be
* retrieved later with the {@link getValue} method.
*
* @param string the new value of the entry. This should be use the
* Latin-1 encoding and be given without any extra NULL characters.
*/
function setValue($str) {
$l = strlen($str);
$this->components = 2 * ($l + 1);
$this->str = $str;
$this->bytes = '';
for ($i = 0; $i < $l; $i++)
$this->bytes .= $str{$i} . chr(0x00);
$this->bytes .= chr(0x00) . chr(0x00);
}
/**
* Return the string of the entry.
*
* @return string the string held, without any extra NULL
* characters. The string will be the same as the one given to
* {@link setValue} or to the {@link __construct constructor}.
*/
function getValue() {
return $this->str;
}
/**
* Return the string of the entry.
*
* This methods returns the same as {@link getValue}.
*
* @param boolean not used.
*
* @return string the string held, without any extra NULL
* characters. The string will be the same as the one given to
* {@link setValue} or to the {@link __construct constructor}.
*/
function getText($brief = false) {
return $this->str;
}
}
?>

View File

@ -0,0 +1,182 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelEntryLong.php 419 2006-02-20 16:22:36Z mgeisler $ */
/**
* Classes used to hold longs, both signed and unsigned.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 419 $
* @date $Date: 2006-02-20 17:22:36 +0100 (Mon, 20 Feb 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelEntryNumber.php');
/**#@-*/
/**
* Class for holding unsigned longs.
*
* This class can hold longs, either just a single long or an array of
* longs. The class will be used to manipulate any of the Exif tags
* which can have format {@link PelFormat::LONG} like in this
* example:
* <code>
* $w = $ifd->getEntry(PelTag::EXIF_IMAGE_WIDTH);
* $w->setValue($w->getValue() / 2);
* $h = $ifd->getEntry(PelTag::EXIF_IMAGE_HEIGHT);
* $h->setValue($h->getValue() / 2);
* </code>
* Here the width and height is updated to 50% of their original
* values.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryLong extends PelEntryNumber {
/**
* Make a new entry that can hold an unsigned long.
*
* The method accept its arguments in two forms: several integer
* arguments or a single array argument. The {@link getValue}
* method will always return an array except for when a single
* integer argument is given here, or when an array with just a
* single integer is given.
*
* This means that one can conveniently use objects like this:
* <code>
* $a = new PelEntryLong(PelTag::EXIF_IMAGE_WIDTH, 123456);
* $b = $a->getValue() - 654321;
* </code>
* where the call to {@link getValue} will return an integer instead
* of an array with one integer element, which would then have to be
* extracted.
*
* @param PelTag the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag},
* e.g., {@link PelTag::IMAGE_WIDTH}, or any other tag which can
* have format {@link PelFormat::LONG}.
*
* @param int $value... the long(s) that this entry will
* represent or an array of longs. The argument passed must obey
* the same rules as the argument to {@link setValue}, namely that
* it should be within range of an unsigned long (32 bit), that is
* between 0 and 4294967295 (inclusive). If not, then a {@link
* PelExifOverflowException} will be thrown.
*/
function __construct($tag /* $value... */) {
$this->tag = $tag;
$this->min = 0;
$this->max = 4294967295;
$this->format = PelFormat::LONG;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int the number that should be converted.
*
* @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
*
* @return string bytes representing the number given.
*/
function numberToBytes($number, $order) {
return PelConvert::longToBytes($number, $order);
}
}
/**
* Class for holding signed longs.
*
* This class can hold longs, either just a single long or an array of
* longs. The class will be used to manipulate any of the Exif tags
* which can have format {@link PelFormat::SLONG}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntrySLong extends PelEntryNumber {
/**
* Make a new entry that can hold a signed long.
*
* The method accept its arguments in two forms: several integer
* arguments or a single array argument. The {@link getValue}
* method will always return an array except for when a single
* integer argument is given here, or when an array with just a
* single integer is given.
*
* @param PelTag the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag}
* which have format {@link PelFormat::SLONG}.
*
* @param int $value... the long(s) that this entry will represent
* or an array of longs. The argument passed must obey the same
* rules as the argument to {@link setValue}, namely that it should
* be within range of a signed long (32 bit), that is between
* -2147483648 and 2147483647 (inclusive). If not, then a {@link
* PelOverflowException} will be thrown.
*/
function __construct($tag /* $value... */) {
$this->tag = $tag;
$this->min = -2147483648;
$this->max = 2147483647;
$this->format = PelFormat::SLONG;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int the number that should be converted.
*
* @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
*
* @return string bytes representing the number given.
*/
function numberToBytes($number, $order) {
return PelConvert::sLongToBytes($number, $order);
}
}
?>

View File

@ -0,0 +1,309 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelEntryNumber.php 419 2006-02-20 16:22:36Z mgeisler $ */
/**
* Abstract class for numbers.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 419 $
* @date $Date: 2006-02-20 17:22:36 +0100 (Mon, 20 Feb 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelException.php');
require_once('PelEntry.php');
/**#@-*/
/**
* Exception cast when numbers overflow.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
class PelOverflowException extends PelException {
/**
* Construct a new overflow exception.
*
* @param int the value that is out of range.
*
* @param int the minimum allowed value.
*
* @param int the maximum allowed value.
*/
function __construct($v, $min, $max) {
parent::__construct('Value %.0f out of range [%.0f, %.0f]',
$v, $min, $max);
}
}
/**
* Class for holding numbers.
*
* This class can hold numbers, with range checks.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
abstract class PelEntryNumber extends PelEntry {
/**
* The value held by this entry.
*
* @var array
*/
protected $value = array();
/**
* The minimum allowed value.
*
* Any attempt to change the value below this variable will result
* in a {@link PelOverflowException} being thrown.
*
* @var int
*/
protected $min;
/**
* The maximum allowed value.
*
* Any attempt to change the value over this variable will result in
* a {@link PelOverflowException} being thrown.
*
* @var int
*/
protected $max;
/**
* The dimension of the number held.
*
* Normal numbers have a dimension of one, pairs have a dimension of
* two, etc.
*
* @var int
*/
protected $dimension = 1;
/**
* Change the value.
*
* This method can change both the number of components and the
* value of the components. Range checks will be made on the new
* value, and a {@link PelOverflowException} will be thrown if the
* value is found to be outside the legal range.
*
* The method accept several number arguments. The {@link getValue}
* method will always return an array except for when a single
* number is given here.
*
* @param int|array $value... the new value(s). This can be zero or
* more numbers, that is, either integers or arrays. The input will
* be checked to ensure that the numbers are within the valid range.
* If not, then a {@link PelOverflowException} will be thrown.
*
* @see getValue
*/
function setValue(/* $value... */) {
$value = func_get_args();
$this->setValueArray($value);
}
/**
* Change the value.
*
* This method can change both the number of components and the
* value of the components. Range checks will be made on the new
* value, and a {@link PelOverflowException} will be thrown if the
* value is found to be outside the legal range.
*
* @param array the new values. The array must contain the new
* numbers.
*
* @see getValue
*/
function setValueArray($value) {
foreach ($value as $v)
$this->validateNumber($v);
$this->components = count($value);
$this->value = $value;
}
/**
* Return the numeric value held.
*
* @return int|array this will either be a single number if there is
* only one component, or an array of numbers otherwise.
*/
function getValue() {
if ($this->components == 1)
return $this->value[0];
else
return $this->value;
}
/**
* Validate a number.
*
* This method will check that the number given is within the range
* given my {@link getMin()} and {@link getMax()}, inclusive. If
* not, then a {@link PelOverflowException} is thrown.
*
* @param int|array the number in question.
*
* @return void nothing, but will throw a {@link
* PelOverflowException} if the number is found to be outside the
* legal range and {@link Pel::$strict} is true.
*/
function validateNumber($n) {
if ($this->dimension == 1) {
if ($n < $this->min || $n > $this->max)
Pel::maybeThrow(new PelOverflowException($n,
$this->min,
$this->max));
} else {
for ($i = 0; $i < $this->dimension; $i++)
if ($n[$i] < $this->min || $n[$i] > $this->max)
Pel::maybeThrow(new PelOverflowException($n[$i],
$this->min,
$this->max));
}
}
/**
* Add a number.
*
* This appends a number to the numbers already held by this entry,
* thereby increasing the number of components by one.
*
* @param int|array the number to be added.
*/
function addNumber($n) {
$this->validateNumber($n);
$this->value[] = $n;
$this->components++;
}
/**
* Convert a number into bytes.
*
* The concrete subclasses will have to implement this method so
* that the numbers represented can be turned into bytes.
*
* The method will be called once for each number held by the entry.
*
* @param int the number that should be converted.
*
* @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
*
* @return string bytes representing the number given.
*/
abstract function numberToBytes($number, $order);
/**
* Turn this entry into bytes.
*
* @param PelByteOrder the desired byte order, which must be either
* {@link PelConvert::LITTLE_ENDIAN} or {@link
* PelConvert::BIG_ENDIAN}.
*
* @return string bytes representing this entry.
*/
function getBytes($o) {
$bytes = '';
for ($i = 0; $i < $this->components; $i++) {
if ($this->dimension == 1) {
$bytes .= $this->numberToBytes($this->value[$i], $o);
} else {
for ($j = 0; $j < $this->dimension; $j++) {
$bytes .= $this->numberToBytes($this->value[$i][$j], $o);
}
}
}
return $bytes;
}
/**
* Format a number.
*
* This method is called by {@link getText} to format numbers.
* Subclasses should override this method if they need more
* sophisticated behavior than the default, which is to just return
* the number as is.
*
* @param int the number which will be formatted.
*
* @param boolean it could be that there is both a verbose and a
* brief formatting available, and this argument controls that.
*
* @return string the number formatted as a string suitable for
* display.
*/
function formatNumber($number, $brief = false) {
return $number;
}
/**
* Get the numeric value of this entry as text.
*
* @param boolean use brief output? The numbers will be separated
* by a single space if brief output is requested, otherwise a space
* and a comma will be used.
*
* @return string the numbers(s) held by this entry.
*/
function getText($brief = false) {
if ($this->components == 0)
return '';
$str = $this->formatNumber($this->value[0]);
for ($i = 1; $i < $this->components; $i++) {
$str .= ($brief ? ' ' : ', ');
$str .= $this->formatNumber($this->value[$i]);
}
return $str;
}
}
?>

View File

@ -0,0 +1,290 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelEntryRational.php 419 2006-02-20 16:22:36Z mgeisler $ */
/**
* Classes used to manipulate rational numbers.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 419 $
* @date $Date: 2006-02-20 17:22:36 +0100 (Mon, 20 Feb 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelEntryLong.php');
/**#@-*/
/**
* Class for holding unsigned rational numbers.
*
* This class can hold rational numbers, consisting of a numerator and
* denominator both of which are of type unsigned long. Each rational
* is represented by an array with just two entries: the numerator and
* the denominator, in that order.
*
* The class can hold either just a single rational or an array of
* rationals. The class will be used to manipulate any of the Exif
* tags which can have format {@link PelFormat::RATIONAL} like in this
* example:
*
* <code>
* $resolution = $ifd->getEntry(PelTag::X_RESOLUTION);
* $resolution->setValue(array(1, 300));
* </code>
*
* Here the x-resolution is adjusted to 1/300, which will be 300 DPI,
* unless the {@link PelTag::RESOLUTION_UNIT resolution unit} is set
* to something different than 2 which means inches.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryRational extends PelEntryLong {
/**
* Make a new entry that can hold an unsigned rational.
*
* @param PelTag the tag which this entry represents. This should
* be one of the constants defined in {@link PelTag}, e.g., {@link
* PelTag::X_RESOLUTION}, or any other tag which can have format
* {@link PelFormat::RATIONAL}.
*
* @param array $value... the rational(s) that this entry will
* represent. The arguments passed must obey the same rules as the
* argument to {@link setValue}, namely that each argument should be
* an array with two entries, both of which must be within range of
* an unsigned long (32 bit), that is between 0 and 4294967295
* (inclusive). If not, then a {@link PelOverflowException} will be
* thrown.
*/
function __construct($tag /* $value... */) {
$this->tag = $tag;
$this->format = PelFormat::RATIONAL;
$this->dimension = 2;
$this->min = 0;
$this->max = 4294967295;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Format a rational number.
*
* The rational will be returned as a string with a slash '/'
* between the numerator and denominator.
*
* @param array the rational which will be formatted.
*
* @param boolean not used.
*
* @return string the rational formatted as a string suitable for
* display.
*/
function formatNumber($number, $brief = false) {
return $number[0] . '/' . $number[1];
}
/**
* Get the value of an entry as text.
*
* The value will be returned in a format suitable for presentation,
* e.g., rationals will be returned as 'x/y', ASCII strings will be
* returned as themselves etc.
*
* @param boolean some values can be returned in a long or more
* brief form, and this parameter controls that.
*
* @return string the value as text.
*/
function getText($brief = false) {
if (isset($this->value[0]))
$v = $this->value[0];
switch ($this->tag) {
case PelTag::FNUMBER:
//CC (e->components, 1, v);
return Pel::fmt('f/%.01f', $v[0]/$v[1]);
case PelTag::APERTURE_VALUE:
//CC (e->components, 1, v);
//if (!v_rat.denominator) return (NULL);
return Pel::fmt('f/%.01f', pow(2, $v[0]/$v[1]/2));
case PelTag::FOCAL_LENGTH:
//CC (e->components, 1, v);
//if (!v_rat.denominator) return (NULL);
return Pel::fmt('%.1f mm', $v[0]/$v[1]);
case PelTag::SUBJECT_DISTANCE:
//CC (e->components, 1, v);
//if (!v_rat.denominator) return (NULL);
return Pel::fmt('%.1f m', $v[0]/$v[1]);
case PelTag::EXPOSURE_TIME:
//CC (e->components, 1, v);
//if (!v_rat.denominator) return (NULL);
if ($v[0]/$v[1] < 1)
return Pel::fmt('1/%d sec.', $v[1]/$v[0]);
else
return Pel::fmt('%d sec.', $v[0]/$v[1]);
case PelTag::GPS_LATITUDE:
case PelTag::GPS_LONGITUDE:
$degrees = $this->value[0][0]/$this->value[0][1];
$minutes = $this->value[1][0]/$this->value[1][1];
$seconds = $this->value[2][0]/$this->value[2][1];
return sprintf('%s° %s\' %s" (%.2f°)',
$degrees, $minutes, $seconds,
$degrees + $minutes/60 + $seconds/3600);
default:
return parent::getText($brief);
}
}
}
/**
* Class for holding signed rational numbers.
*
* This class can hold rational numbers, consisting of a numerator and
* denominator both of which are of type unsigned long. Each rational
* is represented by an array with just two entries: the numerator and
* the denominator, in that order.
*
* The class can hold either just a single rational or an array of
* rationals. The class will be used to manipulate any of the Exif
* tags which can have format {@link PelFormat::SRATIONAL}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntrySRational extends PelEntrySLong {
/**
* Make a new entry that can hold a signed rational.
*
* @param PelTag the tag which this entry represents. This should
* be one of the constants defined in {@link PelTag}, e.g., {@link
* PelTag::SHUTTER_SPEED_VALUE}, or any other tag which can have
* format {@link PelFormat::SRATIONAL}.
*
* @param array $value... the rational(s) that this entry will
* represent. The arguments passed must obey the same rules as the
* argument to {@link setValue}, namely that each argument should be
* an array with two entries, both of which must be within range of
* a signed long (32 bit), that is between -2147483648 and
* 2147483647 (inclusive). If not, then a {@link
* PelOverflowException} will be thrown.
*/
function __construct($tag /* $value... */) {
$this->tag = $tag;
$this->format = PelFormat::SRATIONAL;
$this->dimension = 2;
$this->min = -2147483648;
$this->max = 2147483647;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Format a rational number.
*
* The rational will be returned as a string with a slash '/'
* between the numerator and denominator. Care is taken to display
* '-1/2' instead of the ugly but mathematically equivalent '1/-2'.
*
* @param array the rational which will be formatted.
*
* @param boolean not used.
*
* @return string the rational formatted as a string suitable for
* display.
*/
function formatNumber($number, $brief = false) {
if ($number[1] < 0)
/* Turn output like 1/-2 into -1/2. */
return (-$number[0]) . '/' . (-$number[1]);
else
return $number[0] . '/' . $number[1];
}
/**
* Get the value of an entry as text.
*
* The value will be returned in a format suitable for presentation,
* e.g., rationals will be returned as 'x/y', ASCII strings will be
* returned as themselves etc.
*
* @param boolean some values can be returned in a long or more
* brief form, and this parameter controls that.
*
* @return string the value as text.
*/
function getText($brief = false) {
if (isset($this->value[0]))
$v = $this->value[0];
switch ($this->tag) {
case PelTag::SHUTTER_SPEED_VALUE:
//CC (e->components, 1, v);
//if (!v_srat.denominator) return (NULL);
return Pel::fmt('%.0f/%.0f sec. (APEX: %d)',
$v[0], $v[1], pow(sqrt(2), $v[0]/$v[1]));
case PelTag::BRIGHTNESS_VALUE:
//CC (e->components, 1, v);
//
// TODO: figure out the APEX thing, or remove this so that it is
// handled by the default clause at the bottom.
return sprintf('%d/%d', $v[0], $v[1]);
//FIXME: How do I calculate the APEX value?
case PelTag::EXPOSURE_BIAS_VALUE:
//CC (e->components, 1, v);
//if (!v_srat.denominator) return (NULL);
return sprintf('%s%.01f', $v[0]*$v[1] > 0 ? '+' : '', $v[0]/$v[1]);
default:
return parent::getText($brief);
}
}
}
?>

View File

@ -0,0 +1,599 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelEntryShort.php 419 2006-02-20 16:22:36Z mgeisler $ */
/**
* Classes used to hold shorts, both signed and unsigned.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 419 $
* @date $Date: 2006-02-20 17:22:36 +0100 (Mon, 20 Feb 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelEntryNumber.php');
require_once('PelConvert.php');
require_once('Pel.php');
/**#@-*/
/**
* Class for holding signed shorts.
*
* This class can hold shorts, either just a single short or an array
* of shorts. The class will be used to manipulate any of the Exif
* tags which has format {@link PelFormat::SHORT} like in this
* example:
*
* <code>
* $w = $ifd->getEntry(PelTag::EXIF_IMAGE_WIDTH);
* $w->setValue($w->getValue() / 2);
* $h = $ifd->getEntry(PelTag::EXIF_IMAGE_HEIGHT);
* $h->setValue($h->getValue() / 2);
* </code>
*
* Here the width and height is updated to 50% of their original
* values.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryShort extends PelEntryNumber {
/**
* Make a new entry that can hold an unsigned short.
*
* The method accept several integer arguments. The {@link
* getValue} method will always return an array except for when a
* single integer argument is given here.
*
* This means that one can conveniently use objects like this:
* <code>
* $a = new PelEntryShort(PelTag::EXIF_IMAGE_HEIGHT, 42);
* $b = $a->getValue() + 314;
* </code>
* where the call to {@link getValue} will return an integer
* instead of an array with one integer element, which would then
* have to be extracted.
*
* @param PelTag the tag which this entry represents. This should be
* one of the constants defined in {@link PelTag}, e.g., {@link
* PelTag::IMAGE_WIDTH}, {@link PelTag::ISO_SPEED_RATINGS},
* or any other tag with format {@link PelFormat::SHORT}.
*
* @param int $value... the short(s) that this entry will
* represent. The argument passed must obey the same rules as the
* argument to {@link setValue}, namely that it should be within
* range of an unsigned short, that is between 0 and 65535
* (inclusive). If not, then a {@link PelOverFlowException} will be
* thrown.
*/
function __construct($tag /* $value... */) {
$this->tag = $tag;
$this->min = 0;
$this->max = 65535;
$this->format = PelFormat::SHORT;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int the number that should be converted.
*
* @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
*
* @return string bytes representing the number given.
*/
function numberToBytes($number, $order) {
return PelConvert::shortToBytes($number, $order);
}
/**
* Get the value of an entry as text.
*
* The value will be returned in a format suitable for presentation,
* e.g., instead of returning '2' for a {@link
* PelTag::METERING_MODE} tag, 'Center-Weighted Average' is
* returned.
*
* @param boolean some values can be returned in a long or more
* brief form, and this parameter controls that.
*
* @return string the value as text.
*/
function getText($brief = false) {
switch ($this->tag) {
case PelTag::METERING_MODE:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Unknown');
case 1:
return Pel::tra('Average');
case 2:
return Pel::tra('Center-Weighted Average');
case 3:
return Pel::tra('Spot');
case 4:
return Pel::tra('Multi Spot');
case 5:
return Pel::tra('Pattern');
case 6:
return Pel::tra('Partial');
case 255:
return Pel::tra('Other');
default:
return $this->value[0];
}
case PelTag::COMPRESSION:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 1:
return Pel::tra('Uncompressed');
case 6:
return Pel::tra('JPEG compression');
default:
return $this->value[0];
}
case PelTag::PLANAR_CONFIGURATION:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 1:
return Pel::tra('chunky format');
case 2:
return Pel::tra('planar format');
default:
return $this->value[0];
}
case PelTag::SENSING_METHOD:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 1:
return Pel::tra('Not defined');
case 2:
return Pel::tra('One-chip color area sensor');
case 3:
return Pel::tra('Two-chip color area sensor');
case 4:
return Pel::tra('Three-chip color area sensor');
case 5:
return Pel::tra('Color sequential area sensor');
case 7:
return Pel::tra('Trilinear sensor');
case 8:
return Pel::tra('Color sequential linear sensor');
default:
return $this->value[0];
}
case PelTag::LIGHT_SOURCE:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Unknown');
case 1:
return Pel::tra('Daylight');
case 2:
return Pel::tra('Fluorescent');
case 3:
return Pel::tra('Tungsten (incandescent light)');
case 4:
return Pel::tra('Flash');
case 9:
return Pel::tra('Fine weather');
case 10:
return Pel::tra('Cloudy weather');
case 11:
return Pel::tra('Shade');
case 12:
return Pel::tra('Daylight fluorescent');
case 13:
return Pel::tra('Day white fluorescent');
case 14:
return Pel::tra('Cool white fluorescent');
case 15:
return Pel::tra('White fluorescent');
case 17:
return Pel::tra('Standard light A');
case 18:
return Pel::tra('Standard light B');
case 19:
return Pel::tra('Standard light C');
case 20:
return Pel::tra('D55');
case 21:
return Pel::tra('D65');
case 22:
return Pel::tra('D75');
case 24:
return Pel::tra('ISO studio tungsten');
case 255:
return Pel::tra('Other');
default:
return $this->value[0];
}
case PelTag::FOCAL_PLANE_RESOLUTION_UNIT:
case PelTag::RESOLUTION_UNIT:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 2:
return Pel::tra('Inch');
case 3:
return Pel::tra('Centimeter');
default:
return $this->value[0];
}
case PelTag::EXPOSURE_PROGRAM:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Not defined');
case 1:
return Pel::tra('Manual');
case 2:
return Pel::tra('Normal program');
case 3:
return Pel::tra('Aperture priority');
case 4:
return Pel::tra('Shutter priority');
case 5:
return Pel::tra('Creative program (biased toward depth of field)');
case 6:
return Pel::tra('Action program (biased toward fast shutter speed)');
case 7:
return Pel::tra('Portrait mode (for closeup photos with the background out of focus');
case 8:
return Pel::tra('Landscape mode (for landscape photos with the background in focus');
default:
return $this->value[0];
}
case PelTag::ORIENTATION:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 1:
return Pel::tra('top - left');
case 2:
return Pel::tra('top - right');
case 3:
return Pel::tra('bottom - right');
case 4:
return Pel::tra('bottom - left');
case 5:
return Pel::tra('left - top');
case 6:
return Pel::tra('right - top');
case 7:
return Pel::tra('right - bottom');
case 8:
return Pel::tra('left - bottom');
default:
return $this->value[0];
}
case PelTag::YCBCR_POSITIONING:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 1:
return Pel::tra('centered');
case 2:
return Pel::tra('co-sited');
default:
return $this->value[0];
}
case PelTag::YCBCR_SUB_SAMPLING:
//CC (e->components, 2, v);
if ($this->value[0] == 2 && $this->value[1] == 1)
return 'YCbCr4:2:2';
if ($this->value[0] == 2 && $this->value[1] == 2)
return 'YCbCr4:2:0';
return $this->value[0] . ', ' . $this->value[1];
case PelTag::PHOTOMETRIC_INTERPRETATION:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 2:
return 'RGB';
case 6:
return 'YCbCr';
default:
return $this->value[0];
}
case PelTag::COLOR_SPACE:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 1:
return 'sRGB';
case 2:
return 'Adobe RGB';
case 0xffff:
return Pel::tra('Uncalibrated');
default:
return $this->value[0];
}
case PelTag::FLASH:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0x0000:
return Pel::tra('Flash did not fire.');
case 0x0001:
return Pel::tra('Flash fired.');
case 0x0005:
return Pel::tra('Strobe return light not detected.');
case 0x0007:
return Pel::tra('Strobe return light detected.');
case 0x0009:
return Pel::tra('Flash fired, compulsory flash mode.');
case 0x000d:
return Pel::tra('Flash fired, compulsory flash mode, return light not detected.');
case 0x000f:
return Pel::tra('Flash fired, compulsory flash mode, return light detected.');
case 0x0010:
return Pel::tra('Flash did not fire, compulsory flash mode.');
case 0x0018:
return Pel::tra('Flash did not fire, auto mode.');
case 0x0019:
return Pel::tra('Flash fired, auto mode.');
case 0x001d:
return Pel::tra('Flash fired, auto mode, return light not detected.');
case 0x001f:
return Pel::tra('Flash fired, auto mode, return light detected.');
case 0x0020:
return Pel::tra('No flash function.');
case 0x0041:
return Pel::tra('Flash fired, red-eye reduction mode.');
case 0x0045:
return Pel::tra('Flash fired, red-eye reduction mode, return light not detected.');
case 0x0047:
return Pel::tra('Flash fired, red-eye reduction mode, return light detected.');
case 0x0049:
return Pel::tra('Flash fired, compulsory flash mode, red-eye reduction mode.');
case 0x004d:
return Pel::tra('Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected.');
case 0x004f:
return Pel::tra('Flash fired, compulsory flash mode, red-eye reduction mode, return light detected.');
case 0x0058:
return Pel::tra('Flash did not fire, auto mode, red-eye reduction mode.');
case 0x0059:
return Pel::tra('Flash fired, auto mode, red-eye reduction mode.');
case 0x005d:
return Pel::tra('Flash fired, auto mode, return light not detected, red-eye reduction mode.');
case 0x005f:
return Pel::tra('Flash fired, auto mode, return light detected, red-eye reduction mode.');
default:
return $this->value[0];
}
case PelTag::CUSTOM_RENDERED:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Normal process');
case 1:
return Pel::tra('Custom process');
default:
return $this->value[0];
}
case PelTag::EXPOSURE_MODE:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Auto exposure');
case 1:
return Pel::tra('Manual exposure');
case 2:
return Pel::tra('Auto bracket');
default:
return $this->value[0];
}
case PelTag::WHITE_BALANCE:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Auto white balance');
case 1:
return Pel::tra('Manual white balance');
default:
return $this->value[0];
}
case PelTag::SCENE_CAPTURE_TYPE:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Standard');
case 1:
return Pel::tra('Landscape');
case 2:
return Pel::tra('Portrait');
case 3:
return Pel::tra('Night scene');
default:
return $this->value[0];
}
case PelTag::GAIN_CONTROL:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Normal');
case 1:
return Pel::tra('Low gain up');
case 2:
return Pel::tra('High gain up');
case 3:
return Pel::tra('Low gain down');
case 4:
return Pel::tra('High gain down');
default:
return $this->value[0];
}
case PelTag::SATURATION:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Normal');
case 1:
return Pel::tra('Low saturation');
case 2:
return Pel::tra('High saturation');
default:
return $this->value[0];
}
case PelTag::CONTRAST:
case PelTag::SHARPNESS:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Normal');
case 1:
return Pel::tra('Soft');
case 2:
return Pel::tra('Hard');
default:
return $this->value[0];
}
case PelTag::SUBJECT_DISTANCE_RANGE:
//CC (e->components, 1, v);
switch ($this->value[0]) {
case 0:
return Pel::tra('Unknown');
case 1:
return Pel::tra('Macro');
case 2:
return Pel::tra('Close view');
case 3:
return Pel::tra('Distant view');
default:
return $this->value[0];
}
case PelTag::SUBJECT_AREA:
switch ($this->components) {
case 2:
return Pel::fmt('(x,y) = (%d,%d)', $this->value[0], $this->value[1]);
case 3:
return Pel::fmt('Within distance %d of (x,y) = (%d,%d)',
$this->value[0], $this->value[1], $this->value[2]);
case 4:
return Pel::fmt('Within rectangle (width %d, height %d) around (x,y) = (%d,%d)',
$this->value[0], $this->value[1],
$this->value[2], $this->value[3]);
default:
return Pel::fmt('Unexpected number of components (%d, expected 2, 3, or 4).', $this->components);
}
default:
return parent::getText($brief);
}
}
}
/**
* Class for holding signed shorts.
*
* This class can hold shorts, either just a single short or an array
* of shorts. The class will be used to manipulate any of the Exif
* tags which has format {@link PelFormat::SSHORT}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntrySShort extends PelEntryNumber {
/**
* Make a new entry that can hold a signed short.
*
* The method accept several integer arguments. The {@link
* getValue} method will always return an array except for when a
* single integer argument is given here.
*
* @param PelTag the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag}
* which has format {@link PelFormat::SSHORT}.
*
* @param int $value... the signed short(s) that this entry will
* represent. The argument passed must obey the same rules as the
* argument to {@link setValue}, namely that it should be within
* range of a signed short, that is between -32768 to 32767
* (inclusive). If not, then a {@link PelOverFlowException} will be
* thrown.
*/
function __construct($tag /* $value... */) {
$this->tag = $tag;
$this->min = -32768;
$this->max = 32767;
$this->format = PelFormat::SSHORT;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int the number that should be converted.
*
* @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
*
* @return string bytes representing the number given.
*/
function numberToBytes($number, $order) {
return PelConvert::sShortToBytes($number, $order);
}
}
?>

View File

@ -0,0 +1,416 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelEntryUndefined.php 380 2005-10-03 12:01:28Z mgeisler $ */
/**
* Classes used to hold data for Exif tags of format undefined.
*
* This file contains the base class {@link PelEntryUndefined} and
* the subclasses {@link PelEntryUserComment} which should be used
* to manage the {@link PelTag::USER_COMMENT} tag, and {@link
* PelEntryVersion} which is used to manage entries with version
* information.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 380 $
* @date $Date: 2005-10-03 14:01:28 +0200 (Mon, 03 Oct 2005) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelEntry.php');
/**#@-*/
/**
* Class for holding data of any kind.
*
* This class can hold bytes of undefined format.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryUndefined extends PelEntry {
/**
* Make a new PelEntry that can hold undefined data.
*
* @param PelTag the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag},
* e.g., {@link PelTag::SCENE_TYPE}, {@link
* PelTag::MAKER_NOTE} or any other tag with format {@link
* PelFormat::UNDEFINED}.
*
* @param string the data that this entry will be holding. Since
* the format is undefined, no checking will be done on the data.
*/
function __construct($tag, $data = '') {
$this->tag = $tag;
$this->format = PelFormat::UNDEFINED;
$this->setValue($data);
}
/**
* Set the data of this undefined entry.
*
* @param string the data that this entry will be holding. Since
* the format is undefined, no checking will be done on the data.
*/
function setValue($data) {
$this->components = strlen($data);
$this->bytes = $data;
}
/**
* Get the data of this undefined entry.
*
* @return string the data that this entry is holding.
*/
function getValue() {
return $this->bytes;
}
/**
* Get the value of this entry as text.
*
* The value will be returned in a format suitable for presentation.
*
* @param boolean some values can be returned in a long or more
* brief form, and this parameter controls that.
*
* @return string the value as text.
*/
function getText($brief = false) {
switch ($this->tag) {
case PelTag::FILE_SOURCE:
//CC (e->components, 1, v);
switch (ord($this->bytes{0})) {
case 0x03:
return 'DSC';
default:
return sprintf('0x%02X', ord($this->bytes{0}));
}
case PelTag::SCENE_TYPE:
//CC (e->components, 1, v);
switch (ord($this->bytes{0})) {
case 0x01:
return 'Directly photographed';
default:
return sprintf('0x%02X', ord($this->bytes{0}));
}
case PelTag::COMPONENTS_CONFIGURATION:
//CC (e->components, 4, v);
$v = '';
for ($i = 0; $i < 4; $i++) {
switch (ord($this->bytes{$i})) {
case 0:
$v .= '-';
break;
case 1:
$v .= 'Y';
break;
case 2:
$v .= 'Cb';
break;
case 3:
$v .= 'Cr';
break;
case 4:
$v .= 'R';
break;
case 5:
$v .= 'G';
break;
case 6:
$v .= 'B';
break;
default:
$v .= 'reserved';
break;
}
if ($i < 3) $v .= ' ';
}
return $v;
case PelTag::MAKER_NOTE:
// TODO: handle maker notes.
return $this->components . ' bytes unknown MakerNote data';
default:
return '(undefined)';
}
}
}
/**
* Class for a user comment.
*
* This class is used to hold user comments, which can come in several
* different character encodings. The Exif standard specifies a
* certain format of the {@link PelTag::USER_COMMENT user comment
* tag}, and this class will make sure that the format is kept.
*
* The most basic use of this class simply stores an ASCII encoded
* string for later retrieval using {@link getValue}:
*
* <code>
* $entry = new PelEntryUserComment('An ASCII string');
* echo $entry->getValue();
* </code>
*
* The string can be encoded with a different encoding, and if so, the
* encoding must be given using the second argument. The Exif
* standard specifies three known encodings: 'ASCII', 'JIS', and
* 'Unicode'. If the user comment is encoded using a character
* encoding different from the tree known encodings, then the empty
* string should be passed as encoding, thereby specifying that the
* encoding is undefined.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryUserComment extends PelEntryUndefined {
/**
* The user comment.
*
* @var string
*/
private $comment;
/**
* The encoding.
*
* This should be one of 'ASCII', 'JIS', 'Unicode', or ''.
*
* @var string
*/
private $encoding;
/**
* Make a new entry for holding a user comment.
*
* @param string the new user comment.
*
* @param string the encoding of the comment. This should be either
* 'ASCII', 'JIS', 'Unicode', or the empty string specifying an
* undefined encoding.
*/
function __construct($comment = '', $encoding = 'ASCII') {
parent::__construct(PelTag::USER_COMMENT);
$this->setValue($comment, $encoding);
}
/**
* Set the user comment.
*
* @param string the new user comment.
*
* @param string the encoding of the comment. This should be either
* 'ASCII', 'JIS', 'Unicode', or the empty string specifying an
* unknown encoding.
*/
function setValue($comment = '', $encoding = 'ASCII') {
$this->comment = $comment;
$this->encoding = $encoding;
parent::setValue(str_pad($encoding, 8, chr(0)) . $comment);
}
/**
* Returns the user comment.
*
* The comment is returned with the same character encoding as when
* it was set using {@link setValue} or {@link __construct the
* constructor}.
*
* @return string the user comment.
*/
function getValue() {
return $this->comment;
}
/**
* Returns the encoding.
*
* @return string the encoding of the user comment.
*/
function getEncoding() {
return $this->encoding;
}
/**
* Returns the user comment.
*
* @return string the user comment.
*/
function getText($brief = false) {
return $this->comment;
}
}
/**
* Class to hold version information.
*
* There are three Exif entries that hold version information: the
* {@link PelTag::EXIF_VERSION}, {@link
* PelTag::FLASH_PIX_VERSION}, and {@link
* PelTag::INTEROPERABILITY_VERSION} tags. This class manages
* those tags.
*
* The class is used in a very straight-forward way:
* <code>
* $entry = new PelEntryVersion(PelTag::EXIF_VERSION, 2.2);
* </code>
* This creates an entry for an file complying to the Exif 2.2
* standard. It is easy to test for standards level of an unknown
* entry:
* <code>
* if ($entry->getTag() == PelTag::EXIF_VERSION &&
* $entry->getValue() > 2.0) {
* echo 'Recent Exif version.';
* }
* </code>
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryVersion extends PelEntryUndefined {
/**
* The version held by this entry.
*
* @var float
*/
private $version;
/**
* Make a new entry for holding a version.
*
* @param PelTag the tag. This should be one of {@link
* PelTag::EXIF_VERSION}, {@link PelTag::FLASH_PIX_VERSION},
* or {@link PelTag::INTEROPERABILITY_VERSION}.
*
* @param float the version. The size of the entries leave room for
* exactly four digits: two digits on either side of the decimal
* point.
*/
function __construct($tag, $version = 0.0) {
parent::__construct($tag);
$this->setValue($version);
}
/**
* Set the version held by this entry.
*
* @param float the version. The size of the entries leave room for
* exactly four digits: two digits on either side of the decimal
* point.
*/
function setValue($version = 0.0) {
$this->version = $version;
$major = floor($version);
$minor = ($version - $major)*100;
parent::setValue(sprintf('%02.0f%02.0f', $major, $minor));
}
/**
* Return the version held by this entry.
*
* @return float the version. This will be the same as the value
* given to {@link setValue} or {@link __construct the
* constructor}.
*/
function getValue() {
return $this->version;
}
/**
* Return a text string with the version.
*
* @param boolean controls if the output should be brief. Brief
* output omits the word 'Version' so the result is just 'Exif x.y'
* instead of 'Exif Version x.y' if the entry holds information
* about the Exif version --- the output for FlashPix is similar.
*
* @return string the version number with the type of the tag,
* either 'Exif' or 'FlashPix'.
*/
function getText($brief = false) {
$v = $this->version;
/* Versions numbers like 2.0 would be output as just 2 if we don't
* add the '.0' ourselves. */
if (floor($this->version) == $this->version)
$v .= '.0';
switch ($this->tag) {
case PelTag::EXIF_VERSION:
if ($brief)
return Pel::fmt('Exif %s', $v);
else
return Pel::fmt('Exif Version %s', $v);
case PelTag::FLASH_PIX_VERSION:
if ($brief)
return Pel::fmt('FlashPix %s', $v);
else
return Pel::fmt('FlashPix Version %s', $v);
case PelTag::INTEROPERABILITY_VERSION:
if ($brief)
return Pel::fmt('Interoperability %s', $v);
else
return Pel::fmt('Interoperability Version %s', $v);
}
if ($brief)
return $v;
else
return Pel::fmt('Version %s', $v);
}
}
?>

View File

@ -0,0 +1,87 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelException.php 396 2005-10-23 22:36:10Z mgeisler $ */
/**
* Standard PEL exception.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 396 $
* @date $Date: 2005-10-24 00:36:10 +0200 (Mon, 24 Oct 2005) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* A printf() capable exception.
*
* This class is a simple extension of the standard Exception class in
* PHP, and all the methods defined there retain their original
* meaning.
*
* @package PEL
* @subpackage Exception
*/
class PelException extends Exception {
/**
* Construct a new PEL exception.
*
* @param string $fmt an optional format string can be given. It
* will be used as a format string for vprintf(). The remaining
* arguments will be available for the format string as usual with
* vprintf().
*
* @param mixed $args,... any number of arguments to be used with
* the format string.
*/
function __construct(/* fmt, args... */) {
$args = func_get_args();
$fmt = array_shift($args);
parent::__construct(vsprintf($fmt, $args));
}
}
/**
* Exception throw if invalid data is found.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
class PelInvalidDataException extends PelException {}
/**
* Exception throw if an invalid argument is passed.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
class PelInvalidArgumentException extends PelException {}
?>

View File

@ -0,0 +1,175 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelExif.php 380 2005-10-03 12:01:28Z mgeisler $ */
/**
* Classes for dealing with Exif data.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 380 $
* @date $Date: 2005-10-03 14:01:28 +0200 (Mon, 03 Oct 2005) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelJpegContent.php');
require_once('PelException.php');
require_once('PelFormat.php');
require_once('PelEntry.php');
require_once('PelTiff.php');
require_once('PelIfd.php');
require_once('PelTag.php');
require_once('Pel.php');
/**#@-*/
/**
* Class representing Exif data.
*
* Exif data resides as {@link PelJpegContent data} and consists of a
* header followed by a number of {@link PelJpegIfd IFDs}.
*
* The interesting method in this class is {@link getTiff()} which
* will return the {@link PelTiff} object which really holds the data
* which one normally think of when talking about Exif data. This is
* because Exif data is stored as an extension of the TIFF file
* format.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelExif extends PelJpegContent {
/**
* Exif header.
*
* The Exif data must start with these six bytes to be considered
* valid.
*/
const EXIF_HEADER = "Exif\0\0";
/**
* The PelTiff object contained within.
*
* @var PelTiff
*/
private $tiff = null;
/**
* Construct a new Exif object.
*
* The new object will be empty --- use the {@link load()} method to
* load Exif data from a {@link PelDataWindow} object, or use the
* {@link setTiff()} to change the {@link PelTiff} object, which is
* the true holder of the Exif {@link PelEntry entries}.
*/
function __construct() {
}
/**
* Load and parse Exif data.
*
* This will populate the object with Exif data, contained as a
* {@link PelTiff} object. This TIFF object can be accessed with
* the {@link getTiff()} method.
*/
function load(PelDataWindow $d) {
Pel::debug('Parsing %d bytes of Exif data...', $d->getSize());
/* There must be at least 6 bytes for the Exif header. */
if ($d->getSize() < 6)
throw new PelInvalidDataException('Expected at least 6 bytes of Exif ' .
'data, found just %d bytes.',
$d->getSize());
/* Verify the Exif header */
if ($d->strcmp(0, self::EXIF_HEADER)) {
$d->setWindowStart(strlen(self::EXIF_HEADER));
} else {
throw new PelInvalidDataException('Exif header not found.');
}
/* The rest of the data is TIFF data. */
$this->tiff = new PelTiff();
$this->tiff->load($d);
}
/**
* Change the TIFF information.
*
* Exif data is really stored as TIFF data, and this method can be
* used to change this data from one {@link PelTiff} object to
* another.
*
* @param PelTiff the new TIFF object.
*/
function setTiff(PelTiff $tiff) {
$this->tiff = $tiff;
}
/**
* Get the underlying TIFF object.
*
* The actual Exif data is stored in a {@link PelTiff} object, and
* this method provides access to it.
*
* @return PelTiff the TIFF object with the Exif data.
*/
function getTiff() {
return $this->tiff;
}
/**
* Produce bytes for the Exif data.
*
* @return string bytes representing this object.
*/
function getBytes() {
return self::EXIF_HEADER . $this->tiff->getBytes();
}
/**
* Return a string representation of this object.
*
* @return string a string describing this object. This is mostly
* useful for debugging.
*/
function __toString() {
return Pel::tra("Dumping Exif data...\n") .
$this->tiff->__toString();
}
}
?>

View File

@ -0,0 +1,225 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelFormat.php 380 2005-10-03 12:01:28Z mgeisler $ */
/**
* Namespace for functions operating on Exif formats.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 380 $
* @date $Date: 2005-10-03 14:01:28 +0200 (Mon, 03 Oct 2005) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Namespace for functions operating on Exif formats.
*
* This class defines the constants that are to be used whenever one
* has to refer to the format of an Exif tag. They will be
* collectively denoted by the pseudo-type PelFormat throughout the
* documentation.
*
* All the methods defined here are static, and they all operate on a
* single argument which should be one of the class constants.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelFormat {
/**
* Unsigned byte.
*
* Each component will be an unsigned 8-bit integer with a value
* between 0 and 255.
*
* Modelled with the {@link PelEntryByte} class.
*/
const BYTE = 1;
/**
* ASCII string.
*
* Each component will be an ASCII character.
*
* Modelled with the {@link PelEntryAscii} class.
*/
const ASCII = 2;
/**
* Unsigned short.
*
* Each component will be an unsigned 16-bit integer with a value
* between 0 and 65535.
*
* Modelled with the {@link PelEntryShort} class.
*/
const SHORT = 3;
/**
* Unsigned long.
*
* Each component will be an unsigned 32-bit integer with a value
* between 0 and 4294967295.
*
* Modelled with the {@link PelEntryLong} class.
*/
const LONG = 4;
/**
* Unsigned rational number.
*
* Each component will consist of two unsigned 32-bit integers
* denoting the enumerator and denominator. Each integer will have
* a value between 0 and 4294967295.
*
* Modelled with the {@link PelEntryRational} class.
*/
const RATIONAL = 5;
/**
* Signed byte.
*
* Each component will be a signed 8-bit integer with a value
* between -128 and 127.
*
* Modelled with the {@link PelEntrySByte} class.
*/
const SBYTE = 6;
/**
* Undefined byte.
*
* Each component will be a byte with no associated interpretation.
*
* Modelled with the {@link PelEntryUndefined} class.
*/
const UNDEFINED = 7;
/**
* Signed short.
*
* Each component will be a signed 16-bit integer with a value
* between -32768 and 32767.
*
* Modelled with the {@link PelEntrySShort} class.
*/
const SSHORT = 8;
/**
* Signed long.
*
* Each component will be a signed 32-bit integer with a value
* between -2147483648 and 2147483647.
*
* Modelled with the {@link PelEntrySLong} class.
*/
const SLONG = 9;
/**
* Signed rational number.
*
* Each component will consist of two signed 32-bit integers
* denoting the enumerator and denominator. Each integer will have
* a value between -2147483648 and 2147483647.
*
* Modelled with the {@link PelEntrySRational} class.
*/
const SRATIONAL = 10;
/**
* Floating point number.
*
* Entries with this format are not currently implemented.
*/
const FLOAT = 11;
/**
* Double precision floating point number.
*
* Entries with this format are not currently implemented.
*/
const DOUBLE = 12;
/**
* Returns the name of a format.
*
* @param PelFormat the format.
*
* @return string the name of the format, e.g., 'Ascii' for the
* {@link ASCII} format etc.
*/
static function getName($type) {
switch ($type) {
case self::ASCII: return 'Ascii';
case self::BYTE: return 'Byte';
case self::SHORT: return 'Short';
case self::LONG: return 'Long';
case self::RATIONAL: return 'Rational';
case self::SBYTE: return 'SByte';
case self::SSHORT: return 'SShort';
case self::SLONG: return 'SLong';
case self::SRATIONAL: return 'SRational';
case self::FLOAT: return 'Float';
case self::DOUBLE: return 'Double';
case self::UNDEFINED: return 'Undefined';
default:
return Pel::fmt('Unknown format: 0x%X', $type);
}
}
/**
* Return the size of components in a given format.
*
* @param PelFormat the format.
*
* @return the size in bytes needed to store one component with the
* given format.
*/
static function getSize($type) {
switch ($type) {
case self::ASCII: return 1;
case self::BYTE: return 1;
case self::SHORT: return 2;
case self::LONG: return 4;
case self::RATIONAL: return 8;
case self::SBYTE: return 1;
case self::SSHORT: return 2;
case self::SLONG: return 4;
case self::SRATIONAL: return 8;
case self::FLOAT: return 4;
case self::DOUBLE: return 8;
case self::UNDEFINED: return 1;
default:
return Pel::fmt('Unknown format: 0x%X', $type);
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,599 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelJpeg.php 473 2006-11-23 23:12:21Z mgeisler $ */
/**
* Classes representing JPEG data.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 473 $
* @date $Date: 2006-11-24 00:12:21 +0100 (Fri, 24 Nov 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelJpegComment.php');
require_once('PelJpegContent.php');
require_once('PelDataWindow.php');
require_once('PelJpegMarker.php');
require_once('PelException.php');
require_once('PelExif.php');
require_once('Pel.php');
/**#@-*/
/**
* Exception thrown when an invalid marker is found.
*
* This exception is thrown when PEL expects to find a {@link
* PelJpegMarker} and instead finds a byte that isn't a known marker.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
class PelJpegInvalidMarkerException extends PelException {
/**
* Construct a new invalid marker exception.
*
* The exception will contain a message describing the error,
* including the byte found and the offset of the offending byte.
*
* @param int the byte found.
*
* @param int the offset in the data.
*/
function __construct($marker, $offset) {
parent::__construct('Invalid marker found at offset %d: 0x%2X',
$offset, $marker);
}
}
/**
* Class for handling JPEG data.
*
* The {@link PelJpeg} class defined here provides an abstraction for
* dealing with a JPEG file. The file will be contain a number of
* sections containing some {@link PelJpegContent content} identified
* by a {@link PelJpegMarker marker}.
*
* The {@link getExif()} method is used get hold of the {@link
* PelJpegMarker::APP1 APP1} section which stores Exif data. So if
* the name of the JPEG file is stored in $filename, then one would
* get hold of the Exif data by saying:
*
* <code>
* $jpeg = new PelJpeg($filename);
* $exif = $jpeg->getExif();
* $tiff = $exif->getTiff();
* $ifd0 = $tiff->getIfd();
* $exif = $ifd0->getSubIfd(PelIfd::EXIF);
* $ifd1 = $ifd0->getNextIfd();
* </code>
*
* The $idf0 and $ifd1 variables will then be two {@link PelTiff TIFF}
* {@link PelIfd Image File Directories}, in which the data is stored
* under the keys found in {@link PelTag}.
*
* Should one have some image data (in the form of a {@link
* PelDataWindow}) of an unknown type, then the {@link
* PelJpeg::isValid()} function is handy: it will quickly test if the
* data could be valid JPEG data. The {@link PelTiff::isValid()}
* function does the same for TIFF images.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelJpeg {
/**
* The sections in the JPEG data.
*
* A JPEG file is built up as a sequence of sections, each section
* is identified with a {@link PelJpegMarker}. Some sections can
* occur more than once in the JPEG stream (the {@link
* PelJpegMarker::DQT DQT} and {@link PelJpegMarker::DHT DTH}
* markers for example) and so this is an array of ({@link
* PelJpegMarker}, {@link PelJpegContent}) pairs.
*
* The content can be either generic {@link PelJpegContent JPEG
* content} or {@link PelExif Exif data}.
*
* @var array
*/
private $sections = array();
/**
* The JPEG image data.
*
* @var PelDataWindow
*/
private $jpeg_data = null;
/**
* Construct a new JPEG object.
*
* The new object will be empty unless an argument is given from
* which it can initialize itself. This can either be the filename
* of a JPEG image, a {@link PelDataWindow} object or a PHP image
* resource handle.
*
* New Exif data (in the form of a {@link PelExif} object) can be
* inserted with the {@link setExif()} method:
*
* <code>
* $jpeg = new PelJpeg($data);
* // Create container for the Exif information:
* $exif = new PelExif();
* // Now Add a PelTiff object with a PelIfd object with one or more
* // PelEntry objects to $exif... Finally add $exif to $jpeg:
* $jpeg->setExif($exif);
* </code>
*/
function __construct($data = false) {
if ($data === false)
return;
if (is_string($data)) {
Pel::debug('Initializing PelJpeg object from %s', $data);
$this->loadFile($data);
} elseif ($data instanceof PelDataWindow) {
Pel::debug('Initializing PelJpeg object from PelDataWindow.');
$this->load($data);
} elseif (is_resource($data) && get_resource_type($data) == 'gd') {
Pel::debug('Initializing PelJpeg object from image resource.');
/* The ImageJpeg() function insists on printing the bytes
* instead of returning them in a more civil way as a string, so
* we have to buffer the output... */
ob_start();
ImageJpeg($data);
$bytes = ob_get_clean();
$this->load(new PelDataWindow($bytes));
} else {
throw new PelInvalidArgumentException('Bad type for $data: %s',
gettype($data));
}
}
/**
* Load data into a JPEG object.
*
* The data supplied will be parsed and turned into an object
* structure representing the image. This structure can then be
* manipulated and later turned back into an string of bytes.
*
* This methods can be called at any time after a JPEG object has
* been constructed, also after the {@link appendSection()} has been
* called to append custom sections. Loading several JPEG images
* into one object will accumulate the sections, but there will only
* be one {@link PelJpegMarker::SOS} section at any given time.
*
* @param PelDataWindow the data that will be turned into JPEG
* sections.
*/
function load(PelDataWindow $d) {
Pel::debug('Parsing %d bytes...', $d->getSize());
/* JPEG data is stored in big-endian format. */
$d->setByteOrder(PelConvert::BIG_ENDIAN);
/* Run through the data to read the sections in the image. After
* each section is read, the start of the data window will be
* moved forward, and after the last section we'll terminate with
* no data left in the window. */
while ($d->getSize() > 0) {
/* JPEG sections start with 0xFF. The first byte that is not
* 0xFF is a marker (hopefully).
*/
for ($i = 0; $i < 7; $i++)
if ($d->getByte($i) != 0xFF)
break;
$marker = $d->getByte($i);
if (!PelJpegMarker::isValid($marker))
throw new PelJpegInvalidMarkerException($marker, $i);
/* Move window so first byte becomes first byte in this
* section. */
$d->setWindowStart($i+1);
if ($marker == PelJpegMarker::SOI || $marker == PelJpegMarker::EOI) {
$content = new PelJpegContent(new PelDataWindow());
$this->appendSection($marker, $content);
} else {
/* Read the length of the section. The length includes the
* two bytes used to store the length. */
$len = $d->getShort(0) - 2;
Pel::debug('Found %s section of length %d',
PelJpegMarker::getName($marker), $len);
/* Skip past the length. */
$d->setWindowStart(2);
if ($marker == PelJpegMarker::APP1) {
try {
$content = new PelExif();
$content->load($d->getClone(0, $len));
} catch (PelInvalidDataException $e) {
/* We store the data as normal JPEG content if it could
* not be parsed as Exif data. */
$content = new PelJpegContent($d->getClone(0, $len));
}
$this->appendSection($marker, $content);
/* Skip past the data. */
$d->setWindowStart($len);
} elseif ($marker == PelJpegMarker::COM) {
$content = new PelJpegComment();
$content->load($d->getClone(0, $len));
$this->appendSection($marker, $content);
$d->setWindowStart($len);
} else {
$content = new PelJpegContent($d->getClone(0, $len));
$this->appendSection($marker, $content);
/* Skip past the data. */
$d->setWindowStart($len);
/* In case of SOS, image data will follow. */
if ($marker == PelJpegMarker::SOS) {
/* Some images have some trailing (garbage?) following the
* EOI marker. To handle this we seek backwards until we
* find the EOI marker. Any trailing content is stored as
* a PelJpegContent object. */
$length = $d->getSize();
while ($d->getByte($length-2) != 0xFF ||
$d->getByte($length-1) != PelJpegMarker::EOI) {
$length--;
}
$this->jpeg_data = $d->getClone(0, $length-2);
Pel::debug('JPEG data: ' . $this->jpeg_data->__toString());
/* Append the EOI. */
$this->appendSection(PelJpegMarker::EOI,
new PelJpegContent(new PelDataWindow()));
/* Now check to see if there are any trailing data. */
if ($length != $d->getSize()) {
Pel::maybeThrow(new PelException('Found trailing content ' .
'after EOI: %d bytes',
$d->getSize() - $length));
$content = new PelJpegContent($d->getClone($length));
/* We don't have a proper JPEG marker for trailing
* garbage, so we just use 0x00... */
$this->appendSection(0x00, $content);
}
/* Done with the loop. */
break;
}
}
}
} /* while ($d->getSize() > 0) */
}
/**
* Load data from a file into a JPEG object.
*
* @param string the filename. This must be a readable file.
*/
function loadFile($filename) {
$this->load(new PelDataWindow(file_get_contents($filename)));
}
/**
* Set Exif data.
*
* Use this to set the Exif data in the image. This will overwrite
* any old Exif information in the image.
*
* @param PelExif the Exif data.
*/
function setExif(PelExif $exif) {
$app0_offset = 1;
$app1_offset = -1;
/* Search through all sections looking for APP0 or APP1. */
for ($i = 0; $i < count($this->sections); $i++) {
if ($this->sections[$i][0] == PelJpegMarker::APP0) {
$app0_offset = $i;
} elseif ($this->sections[$i][0] == PelJpegMarker::APP1) {
$app1_offset = $i;
break;
}
}
/* Store the Exif data at the appropriate place, either where the
* old Exif data was stored ($app1_offset) or right after APP0
* ($app0_offset+1). */
if ($app1_offset > 0)
$this->sections[$app1_offset][1] = $exif;
else
$this->insertSection(PelJpegMarker::APP1, $exif, $app0_offset+1);
}
/**
* Get Exif data.
*
* Use this to get the @{link PelExif Exif data} stored.
*
* @return PelExif the Exif data found or null if the image has no
* Exif data.
*/
function getExif() {
$exif = $this->getSection(PelJpegMarker::APP1);
if ($exif instanceof PelExif)
return $exif;
else
return null;
}
/**
* Clear any Exif data.
*
* This method will only clear the first @{link PelJpegMarker::APP1}
* section found (there should normally be just one).
*/
function clearExif() {
for ($i = 0; $i < count($this->sections); $i++) {
if ($this->sections[$i][0] == PelJpegMarker::APP1) {
unset($this->sections[$i]);
return;
}
}
}
/**
* Append a new section.
*
* Used only when loading an image. If it used again later, then the
* section will end up after the @{link PelJpegMarker::EOI EOI
* marker} and will probably not be useful.
*
* Please use @{link setExif()} instead if you intend to add Exif
* information to an image as that function will know the right
* place to insert the data.
*
* @param PelJpegMarker the marker identifying the new section.
*
* @param PelJpegContent the content of the new section.
*/
function appendSection($marker, PelJpegContent $content) {
$this->sections[] = array($marker, $content);
}
/**
* Insert a new section.
*
* Please use @{link setExif()} instead if you intend to add Exif
* information to an image as that function will know the right
* place to insert the data.
*
* @param PelJpegMarker the marker for the new section.
*
* @param PelJpegContent the content of the new section.
*
* @param int the offset where the new section will be inserted ---
* use 0 to insert it at the very beginning, use 1 to insert it
* between sections 1 and 2, etc.
*/
function insertSection($marker, PelJpegContent $content, $offset) {
array_splice($this->sections, $offset, 0, array(array($marker, $content)));
}
/**
* Get a section corresponding to a particular marker.
*
* Please use the {@link getExif()} if you just need the Exif data.
*
* This will search through the sections of this JPEG object,
* looking for a section identified with the specified {@link
* PelJpegMarker marker}. The {@link PelJpegContent content} will
* then be returned. The optional argument can be used to skip over
* some of the sections. So if one is looking for the, say, third
* {@link PelJpegMarker::DHT DHT} section one would do:
*
* <code>
* $dht3 = $jpeg->getSection(PelJpegMarker::DHT, 2);
* </code>
*
* @param PelJpegMarker the marker identifying the section.
*
* @param int the number of sections to be skipped. This must be a
* non-negative integer.
*
* @return PelJpegContent the content found, or null if there is no
* content available.
*/
function getSection($marker, $skip = 0) {
foreach ($this->sections as $s) {
if ($s[0] == $marker)
if ($skip > 0)
$skip--;
else
return $s[1];
}
return null;
}
/**
* Get all sections.
*
* @return array an array of ({@link PelJpegMarker}, {@link
* PelJpegContent}) pairs. Each pair is an array with the {@link
* PelJpegMarker} as the first element and the {@link
* PelJpegContent} as the second element, so the return type is an
* array of arrays.
*
* So to loop through all the sections in a given JPEG image do
* this:
*
* <code>
* foreach ($jpeg->getSections() as $section) {
* $marker = $section[0];
* $content = $section[1];
* // Use $marker and $content here.
* }
* </code>
*
* instead of this:
*
* <code>
* foreach ($jpeg->getSections() as $marker => $content) {
* // Does not work the way you would think...
* }
* </code>
*
* The problem is that there could be several sections with the same
* marker, and thus a simple associative array does not suffice.
*/
function getSections() {
return $this->sections;
}
/**
* Turn this JPEG object into bytes.
*
* The bytes returned by this method is ready to be stored in a file
* as a valid JPEG image.
*
* @return string bytes representing this JPEG object, including all
* its sections and their associated data.
*/
function getBytes() {
$bytes = '';
foreach ($this->sections as $section) {
$m = $section[0];
$c = $section[1];
/* Write the marker */
$bytes .= "\xFF" . PelJpegMarker::getBytes($m);
/* Skip over empty markers. */
if ($m == PelJpegMarker::SOI || $m == PelJpegMarker::EOI)
continue;
$data = $c->getBytes();
$size = strlen($data) + 2;
$bytes .= PelConvert::shortToBytes($size, PelConvert::BIG_ENDIAN);
$bytes .= $data;
/* In case of SOS, we need to write the JPEG data. */
if ($m == PelJpegMarker::SOS)
$bytes .= $this->jpeg_data->getBytes();
}
return $bytes;
}
/**
* Make a string representation of this JPEG object.
*
* This is mainly usefull for debugging. It will show the structure
* of the image, and its sections.
*
* @return string debugging information about this JPEG object.
*/
function __toString() {
$str = Pel::tra("Dumping JPEG data...\n");
for ($i = 0; $i < count($this->sections); $i++) {
$m = $this->sections[$i][0];
$c = $this->sections[$i][1];
$str .= Pel::fmt("Section %d (marker 0x%02X - %s):\n",
$i, $m, PelJpegMarker::getName($m));
$str .= Pel::fmt(" Description: %s\n",
PelJpegMarker::getDescription($m));
if ($m == PelJpegMarker::SOI ||
$m == PelJpegMarker::EOI)
continue;
if ($c instanceof PelExif) {
$str .= Pel::tra(" Content : Exif data\n");
$str .= $c->__toString() . "\n";
} elseif ($c instanceof PelJpegComment) {
$str .= Pel::fmt(" Content : %s\n", $c->getValue());
} else {
$str .= Pel::tra(" Content : Unknown\n");
}
}
return $str;
}
/**
* Test data to see if it could be a valid JPEG image.
*
* The function will only look at the first few bytes of the data,
* and try to determine if it could be a valid JPEG image based on
* those bytes. This means that the check is more like a heuristic
* than a rigorous check.
*
* @param PelDataWindow the bytes that will be checked.
*
* @return boolean true if the bytes look like the beginning of a
* JPEG image, false otherwise.
*
* @see PelTiff::isValid()
*/
static function isValid(PelDataWindow $d) {
/* JPEG data is stored in big-endian format. */
$d->setByteOrder(PelConvert::BIG_ENDIAN);
for ($i = 0; $i < 7; $i++)
if ($d->getByte($i) != 0xFF)
break;
return $d->getByte($i) == PelJpegMarker::SOI;
}
}
?>

View File

@ -0,0 +1,121 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2005 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelJpegComment.php 397 2005-10-23 22:40:26Z mgeisler $ */
/**
* Class for dealing with JPEG comments.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 397 $
* @date $Date: 2005-10-24 00:40:26 +0200 (Mon, 24 Oct 2005) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelJpegContent.php');
/**#@-*/
/**
* Class representing JPEG comments.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelJpegComment extends PelJpegContent {
/**
* The comment.
*
* @var string
*/
private $comment = '';
/**
* Construct a new JPEG comment.
*
* The new comment will contain the string given.
*/
function __construct($comment = '') {
$this->comment = $comment;
}
/**
* Load and parse data.
*
* This will load the comment from the data window passed.
*/
function load(PelDataWindow $d) {
$this->comment = $d->getBytes();
}
/**
* Update the value with a new comment.
*
* Any old comment will be overwritten.
*
* @param string the new comment.
*/
function setValue($comment) {
$this->comment = $comment;
}
/**
* Get the comment.
*
* @return string the comment.
*/
function getValue() {
return $this->comment;
}
/**
* Turn this comment into bytes.
*
* @return string bytes representing this comment.
*/
function getBytes() {
$this->comment;
}
/**
* Return a string representation of this object.
*
* @return string the same as {@link getValue()}.
*/
function __toString() {
return $this->getValue();
}
}
?>

View File

@ -0,0 +1,82 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelJpegContent.php 380 2005-10-03 12:01:28Z mgeisler $ */
/**
* Class representing content in a JPEG file.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 380 $
* @date $Date: 2005-10-03 14:01:28 +0200 (Mon, 03 Oct 2005) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelDataWindow.php');
/**#@-*/
/**
* Class representing content in a JPEG file.
*
* A JPEG file consists of a sequence of each of which has an
* associated {@link PelJpegMarker marker} and some content. This
* class represents the content, and this basic type is just a simple
* holder of such content, represented by a {@link PelDataWindow}
* object. The {@link PelExif} class is an example of more
* specialized JPEG content.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelJpegContent {
private $data = null;
/**
* Make a new piece of JPEG content.
*
* @param PelDataWindow the content.
*/
function __construct(PelDataWindow $data) {
$this->data = $data;
}
/**
* Return the bytes of the content.
*
* @return string bytes representing this JPEG content. These bytes
* will match the bytes given to {@link __construct the
* constructor}.
*/
function getBytes() {
return $this->data->getBytes();
}
}
?>

View File

@ -0,0 +1,435 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelJpegMarker.php 432 2006-09-05 22:13:00Z mgeisler $ */
/**
* Classes for dealing with JPEG markers.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 432 $
* @date $Date: 2006-09-06 00:13:00 +0200 (Wed, 06 Sep 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('Pel.php');
/**#@-*/
/**
* Class with static methods for JPEG markers.
*
* This class defines the constants to be used whenever one refers to
* a JPEG marker. All the methods defined are static, and they all
* operate on one argument which should be one of the class constants.
* They will all be denoted by PelJpegMarker in the documentation.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelJpegMarker {
/** Encoding (baseline) */
const SOF0 = 0xC0;
/** Encoding (extended sequential) */
const SOF1 = 0xC1;
/** Encoding (progressive) */
const SOF2 = 0xC2;
/** Encoding (lossless) */
const SOF3 = 0xC3;
/** Define Huffman table */
const DHT = 0xC4;
/** Encoding (differential sequential) */
const SOF5 = 0xC5;
/** Encoding (differential progressive) */
const SOF6 = 0xC6;
/** Encoding (differential lossless) */
const SOF7 = 0xC7;
/** Extension */
const JPG = 0xC8;
/** Encoding (extended sequential, arithmetic) */
const SOF9 = 0xC9;
/** Encoding (progressive, arithmetic) */
const SOF10 = 0xCA;
/** Encoding (lossless, arithmetic) */
const SOF11 = 0xCB;
/** Define arithmetic coding conditioning */
const DAC = 0xCC;
/** Encoding (differential sequential, arithmetic) */
const SOF13 = 0xCD;
/** Encoding (differential progressive, arithmetic) */
const SOF14 = 0xCE;
/** Encoding (differential lossless, arithmetic) */
const SOF15 = 0xCF;
/** Restart 0 */
const RST0 = 0xD0;
/** Restart 1 */
const RST1 = 0xD1;
/** Restart 2 */
const RST2 = 0xD2;
/** Restart 3 */
const RST3 = 0xD3;
/** Restart 4 */
const RST4 = 0xD4;
/** Restart 5 */
const RST5 = 0xD5;
/** Restart 6 */
const RST6 = 0xD6;
/** Restart 7 */
const RST7 = 0xD7;
/** Start of image */
const SOI = 0xD8;
/** End of image */
const EOI = 0xD9;
/** Start of scan */
const SOS = 0xDA;
/** Define quantization table */
const DQT = 0xDB;
/** Define number of lines */
const DNL = 0xDC;
/** Define restart interval */
const DRI = 0xDD;
/** Define hierarchical progression */
const DHP = 0xDE;
/** Expand reference component */
const EXP = 0xDF;
/** Application segment 0 */
const APP0 = 0xE0;
/**
* Application segment 1
*
* When a JPEG image contains Exif data, the data will normally be
* stored in this section and a call to {@link PelJpeg::getExif()}
* will return a {@link PelExif} object representing it.
*/
const APP1 = 0xE1;
/** Application segment 2 */
const APP2 = 0xE2;
/** Application segment 3 */
const APP3 = 0xE3;
/** Application segment 4 */
const APP4 = 0xE4;
/** Application segment 5 */
const APP5 = 0xE5;
/** Application segment 6 */
const APP6 = 0xE6;
/** Application segment 7 */
const APP7 = 0xE7;
/** Application segment 8 */
const APP8 = 0xE8;
/** Application segment 9 */
const APP9 = 0xE9;
/** Application segment 10 */
const APP10 = 0xEA;
/** Application segment 11 */
const APP11 = 0xEB;
/** Application segment 12 */
const APP12 = 0xEC;
/** Application segment 13 */
const APP13 = 0xED;
/** Application segment 14 */
const APP14 = 0xEE;
/** Application segment 15 */
const APP15 = 0xEF;
/** Extension 0 */
const JPG0 = 0xF0;
/** Extension 1 */
const JPG1 = 0xF1;
/** Extension 2 */
const JPG2 = 0xF2;
/** Extension 3 */
const JPG3 = 0xF3;
/** Extension 4 */
const JPG4 = 0xF4;
/** Extension 5 */
const JPG5 = 0xF5;
/** Extension 6 */
const JPG6 = 0xF6;
/** Extension 7 */
const JPG7 = 0xF7;
/** Extension 8 */
const JPG8 = 0xF8;
/** Extension 9 */
const JPG9 = 0xF9;
/** Extension 10 */
const JPG10 = 0xFA;
/** Extension 11 */
const JPG11 = 0xFB;
/** Extension 12 */
const JPG12 = 0xFC;
/** Extension 13 */
const JPG13 = 0xFD;
/** Comment */
const COM = 0xFE;
/**
* Check if a byte is a valid JPEG marker.
*
* @param PelJpegMarker the byte that will be checked.
*
* @return boolean if the byte is recognized true is returned,
* otherwise false will be returned.
*/
static function isValid($m) {
return ($m >= self::SOF0 && $m <= self::COM);
}
/**
* Turn a JPEG marker into bytes.
*
* @param PelJpegMarker the marker.
*
* @return string the marker as a string. This will be a string
* with just a single byte since all JPEG markers are simply single
* bytes.
*/
static function getBytes($m) {
return chr($m);
}
/**
* Return the short name for a marker.
*
* @param PelJpegMarker the marker.
*
* @return string the name of the marker, e.g., 'SOI' for the Start
* of Image marker.
*/
static function getName($m) {
switch ($m) {
case self::SOF0: return 'SOF0';
case self::SOF1: return 'SOF1';
case self::SOF2: return 'SOF2';
case self::SOF3: return 'SOF3';
case self::SOF5: return 'SOF5';
case self::SOF6: return 'SOF6';
case self::SOF7: return 'SOF7';
case self::SOF9: return 'SOF9';
case self::SOF10: return 'SOF10';
case self::SOF11: return 'SOF11';
case self::SOF13: return 'SOF13';
case self::SOF14: return 'SOF14';
case self::SOF15: return 'SOF15';
case self::SOI: return 'SOI';
case self::EOI: return 'EOI';
case self::SOS: return 'SOS';
case self::COM: return 'COM';
case self::DHT: return 'DHT';
case self::JPG: return 'JPG';
case self::DAC: return 'DAC';
case self::RST0: return 'RST0';
case self::RST1: return 'RST1';
case self::RST2: return 'RST2';
case self::RST3: return 'RST3';
case self::RST4: return 'RST4';
case self::RST5: return 'RST5';
case self::RST6: return 'RST6';
case self::RST7: return 'RST7';
case self::DQT: return 'DQT';
case self::DNL: return 'DNL';
case self::DRI: return 'DRI';
case self::DHP: return 'DHP';
case self::EXP: return 'EXP';
case self::APP0: return 'APP0';
case self::APP1: return 'APP1';
case self::APP2: return 'APP2';
case self::APP3: return 'APP3';
case self::APP4: return 'APP4';
case self::APP5: return 'APP5';
case self::APP6: return 'APP6';
case self::APP7: return 'APP7';
case self::APP8: return 'APP8';
case self::APP9: return 'APP9';
case self::APP10: return 'APP10';
case self::APP11: return 'APP11';
case self::APP12: return 'APP12';
case self::APP13: return 'APP13';
case self::APP14: return 'APP14';
case self::APP15: return 'APP15';
case self::JPG0: return 'JPG0';
case self::JPG1: return 'JPG1';
case self::JPG2: return 'JPG2';
case self::JPG3: return 'JPG3';
case self::JPG4: return 'JPG4';
case self::JPG5: return 'JPG5';
case self::JPG6: return 'JPG6';
case self::JPG7: return 'JPG7';
case self::JPG8: return 'JPG8';
case self::JPG9: return 'JPG9';
case self::JPG10: return 'JPG10';
case self::JPG11: return 'JPG11';
case self::JPG12: return 'JPG12';
case self::JPG13: return 'JPG13';
case self::COM: return 'COM';
default: return Pel::fmt('Unknown marker: 0x%02X', $m);
}
}
/**
* Returns a description of a JPEG marker.
*
* @param PelJpegMarker the marker.
*
* @return string the description of the marker.
*/
static function getDescription($m) {
switch ($m) {
case self::SOF0:
return Pel::tra('Encoding (baseline)');
case self::SOF1:
return Pel::tra('Encoding (extended sequential)');
case self::SOF2:
return Pel::tra('Encoding (progressive)');
case self::SOF3:
return Pel::tra('Encoding (lossless)');
case self::SOF5:
return Pel::tra('Encoding (differential sequential)');
case self::SOF6:
return Pel::tra('Encoding (differential progressive)');
case self::SOF7:
return Pel::tra('Encoding (differential lossless)');
case self::SOF9:
return Pel::tra('Encoding (extended sequential, arithmetic)');
case self::SOF10:
return Pel::tra('Encoding (progressive, arithmetic)');
case self::SOF11:
return Pel::tra('Encoding (lossless, arithmetic)');
case self::SOF13:
return Pel::tra('Encoding (differential sequential, arithmetic)');
case self::SOF14:
return Pel::tra('Encoding (differential progressive, arithmetic)');
case self::SOF15:
return Pel::tra('Encoding (differential lossless, arithmetic)');
case self::SOI:
return Pel::tra('Start of image');
case self::EOI:
return Pel::tra('End of image');
case self::SOS:
return Pel::tra('Start of scan');
case self::COM:
return Pel::tra('Comment');
case self::DHT:
return Pel::tra('Define Huffman table');
case self::JPG:
return Pel::tra('Extension');
case self::DAC:
return Pel::tra('Define arithmetic coding conditioning');
case self::RST0:
return Pel::fmt('Restart %d', 0);
case self::RST1:
return Pel::fmt('Restart %d', 1);
case self::RST2:
return Pel::fmt('Restart %d', 2);
case self::RST3:
return Pel::fmt('Restart %d', 3);
case self::RST4:
return Pel::fmt('Restart %d', 4);
case self::RST5:
return Pel::fmt('Restart %d', 5);
case self::RST6:
return Pel::fmt('Restart %d', 6);
case self::RST7:
return Pel::fmt('Restart %d', 7);
case self::DQT:
return Pel::tra('Define quantization table');
case self::DNL:
return Pel::tra('Define number of lines');
case self::DRI:
return Pel::tra('Define restart interval');
case self::DHP:
return Pel::tra('Define hierarchical progression');
case self::EXP:
return Pel::tra('Expand reference component');
case self::APP0:
return Pel::fmt('Application segment %d', 0);
case self::APP1:
return Pel::fmt('Application segment %d', 1);
case self::APP2:
return Pel::fmt('Application segment %d', 2);
case self::APP3:
return Pel::fmt('Application segment %d', 3);
case self::APP4:
return Pel::fmt('Application segment %d', 4);
case self::APP5:
return Pel::fmt('Application segment %d', 5);
case self::APP6:
return Pel::fmt('Application segment %d', 6);
case self::APP7:
return Pel::fmt('Application segment %d', 7);
case self::APP8:
return Pel::fmt('Application segment %d', 8);
case self::APP9:
return Pel::fmt('Application segment %d', 9);
case self::APP10:
return Pel::fmt('Application segment %d', 10);
case self::APP11:
return Pel::fmt('Application segment %d', 11);
case self::APP12:
return Pel::fmt('Application segment %d', 12);
case self::APP13:
return Pel::fmt('Application segment %d', 13);
case self::APP14:
return Pel::fmt('Application segment %d', 14);
case self::APP15:
return Pel::fmt('Application segment %d', 15);
case self::JPG0:
return Pel::fmt('Extension %d', 0);
case self::JPG1:
return Pel::fmt('Extension %d', 1);
case self::JPG2:
return Pel::fmt('Extension %d', 2);
case self::JPG3:
return Pel::fmt('Extension %d', 3);
case self::JPG4:
return Pel::fmt('Extension %d', 4);
case self::JPG5:
return Pel::fmt('Extension %d', 5);
case self::JPG6:
return Pel::fmt('Extension %d', 6);
case self::JPG7:
return Pel::fmt('Extension %d', 7);
case self::JPG8:
return Pel::fmt('Extension %d', 8);
case self::JPG9:
return Pel::fmt('Extension %d', 9);
case self::JPG10:
return Pel::fmt('Extension %d', 10);
case self::JPG11:
return Pel::fmt('Extension %d', 11);
case self::JPG12:
return Pel::fmt('Extension %d', 12);
case self::JPG13:
return Pel::fmt('Extension %d', 13);
case self::COM:
return Pel::tra('Comment');
default:
return Pel::fmt('Unknown marker: 0x%02X', $m);
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,296 @@
<?php
/* PEL: PHP Exif Library. A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* 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 2 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 in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/* $Id: PelTiff.php 458 2006-11-18 21:22:58Z mgeisler $ */
/**
* Classes for dealing with TIFF data.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @version $Revision: 458 $
* @date $Date: 2006-11-18 22:22:58 +0100 (Sat, 18 Nov 2006) $
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**#@+ Required class definitions. */
require_once('PelDataWindow.php');
require_once('PelIfd.php');
require_once('Pel.php');
/**#@-*/
/**
* Class for handling TIFF data.
*
* Exif data is actually an extension of the TIFF file format. TIFF
* images consist of a number of {@link PelIfd Image File Directories}
* (IFDs), each containing a number of {@link PelEntry entries}. The
* IFDs are linked to each other --- one can get hold of the first one
* with the {@link getIfd()} method.
*
* To parse a TIFF image for Exif data one would do:
*
* <code>
* $tiff = new PelTiff($data);
* $ifd0 = $tiff->getIfd();
* $exif = $ifd0->getSubIfd(PelIfd::EXIF);
* $ifd1 = $ifd0->getNextIfd();
* </code>
*
* Should one have some image data of an unknown type, then the {@link
* PelTiff::isValid()} function is handy: it will quickly test if the
* data could be valid TIFF data. The {@link PelJpeg::isValid()}
* function does the same for JPEG images.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelTiff {
/**
* TIFF header.
*
* This must follow after the two bytes indicating the byte order.
*/
const TIFF_HEADER = 0x002A;
/**
* The first Image File Directory, if any.
*
* If set, then the type of the IFD must be {@link PelIfd::IFD0}.
*
* @var PelIfd
*/
private $ifd = null;
/**
* Construct a new object for holding TIFF data.
*
* The new object will be empty (with no {@link PelIfd}) unless an
* argument is given from which it can initialize itself. This can
* either be the filename of a TIFF image or a {@link PelDataWindow}
* object.
*
* Use {@link setIfd()} to explicitly set the IFD.
*/
function __construct($data = false) {
if ($data === false)
return;
if (is_string($data)) {
Pel::debug('Initializing PelTiff object from %s', $data);
$this->loadFile($data);
} elseif ($data instanceof PelDataWindow) {
Pel::debug('Initializing PelTiff object from PelDataWindow.');
$this->load($data);
} else {
throw new PelInvalidArgumentException('Bad type for $data: %s',
gettype($data));
}
}
/**
* Load TIFF data.
*
* The data given will be parsed and an internal tree representation
* will be built. If the data cannot be parsed correctly, a {@link
* PelInvalidDataException} is thrown, explaining the problem.
*
* @param PelDataWindow the data from which the object will be
* constructed. This should be valid TIFF data, coming either
* directly from a TIFF image or from the Exif data in a JPEG image.
*/
function load(PelDataWindow $d) {
Pel::debug('Parsing %d bytes of TIFF data...', $d->getSize());
/* There must be at least 8 bytes available: 2 bytes for the byte
* order, 2 bytes for the TIFF header, and 4 bytes for the offset
* to the first IFD. */
if ($d->getSize() < 8)
throw new PelInvalidDataException('Expected at least 8 bytes of TIFF ' .
'data, found just %d bytes.',
$d->getSize());
/* Byte order */
if ($d->strcmp(0, 'II')) {
Pel::debug('Found Intel byte order');
$d->setByteOrder(PelConvert::LITTLE_ENDIAN);
} elseif ($d->strcmp(0, 'MM')) {
Pel::debug('Found Motorola byte order');
$d->setByteOrder(PelConvert::BIG_ENDIAN);
} else {
throw new PelInvalidDataException('Unknown byte order found in TIFF ' .
'data: 0x%2X%2X',
$d->getByte(0), $d->getByte(1));
}
/* Verify the TIFF header */
if ($d->getShort(2) != self::TIFF_HEADER)
throw new PelInvalidDataException('Missing TIFF magic value.');
/* IFD 0 offset */
$offset = $d->getLong(4);
Pel::debug('First IFD at offset %d.', $offset);
if ($offset > 0) {
/* Parse the first IFD, this will automatically parse the
* following IFDs and any sub IFDs. */
$this->ifd = new PelIfd(PelIfd::IFD0);
$this->ifd->load($d, $offset);
}
}
/**
* Load data from a file into a TIFF object.
*
* @param string the filename. This must be a readable file.
*/
function loadFile($filename) {
$this->load(new PelDataWindow(file_get_contents($filename)));
}
/**
* Set the first IFD.
*
* @param PelIfd the new first IFD, which must be of type {@link
* PelIfd::IFD0}.
*/
function setIfd(PelIfd $ifd) {
if ($ifd->getType() != PelIfd::IFD0)
throw new PelInvalidDataException('Invalid type of IFD: %d, expected %d.',
$ifd->getType(), PelIfd::IFD0);
$this->ifd = $ifd;
}
/**
* Return the first IFD.
*
* @return PelIfd the first IFD contained in the TIFF data, if any.
* If there is no IFD null will be returned.
*/
function getIfd() {
return $this->ifd;
}
/**
* Turn this object into bytes.
*
* TIFF images can have {@link PelConvert::LITTLE_ENDIAN
* little-endian} or {@link PelConvert::BIG_ENDIAN big-endian} byte
* order, and so this method takes an argument specifying that.
*
* @param PelByteOrder the desired byte order of the TIFF data.
* This should be one of {@link PelConvert::LITTLE_ENDIAN} or {@link
* PelConvert::BIG_ENDIAN}.
*
* @return string the bytes representing this object.
*/
function getBytes($order = PelConvert::LITTLE_ENDIAN) {
if ($order == PelConvert::LITTLE_ENDIAN)
$bytes = 'II';
else
$bytes = 'MM';
/* TIFF magic number --- fixed value. */
$bytes .= PelConvert::shortToBytes(self::TIFF_HEADER, $order);
if ($this->ifd != null) {
/* IFD 0 offset. We will always start IDF 0 at an offset of 8
* bytes (2 bytes for byte order, another 2 bytes for the TIFF
* header, and 4 bytes for the IFD 0 offset make 8 bytes
* together).
*/
$bytes .= PelConvert::longToBytes(8, $order);
/* The argument specifies the offset of this IFD. The IFD will
* use this to calculate offsets from the entries to their data,
* all those offsets are absolute offsets counted from the
* beginning of the data. */
$bytes .= $this->ifd->getBytes(8, $order);
} else {
$bytes .= PelConvert::longToBytes(0, $order);
}
return $bytes;
}
/**
* Return a string representation of this object.
*
* @return string a string describing this object. This is mostly useful
* for debugging.
*/
function __toString() {
$str = Pel::fmt("Dumping TIFF data...\n");
if ($this->ifd != null)
$str .= $this->ifd->__toString();
return $str;
}
/**
* Check if data is valid TIFF data.
*
* This will read just enough data from the data window to determine
* if the data could be a valid TIFF data. This means that the
* check is more like a heuristic than a rigorous check.
*
* @param PelDataWindow the bytes that will be examined.
*
* @return boolean true if the data looks like valid TIFF data,
* false otherwise.
*
* @see PelJpeg::isValid()
*/
static function isValid(PelDataWindow $d) {
/* First check that we have enough data. */
if ($d->getSize() < 8)
return false;
/* Byte order */
if ($d->strcmp(0, 'II')) {
$d->setByteOrder(PelConvert::LITTLE_ENDIAN);
} elseif ($d->strcmp(0, 'MM')) {
Pel::debug('Found Motorola byte order');
$d->setByteOrder(PelConvert::BIG_ENDIAN);
} else {
return false;
}
/* Verify the TIFF header */
return $d->getShort(2) == self::TIFF_HEADER;
}
}

View File

@ -0,0 +1,3 @@
name = "Autorotate"
description = "Rotate an image automatically on upload based on EXIF data"
version = 2

View File

@ -0,0 +1,163 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class Admin_Configure_Controller extends Controller
{
/**
* the index page of the user homes admin
*/
public function index()
{
$form = basket::get_configure_form();
if (request::method() == "post") {
access::verify_csrf();
if ($form->validate()) {
basket::extractForm($form);
message::success(t("Basket Module Configured!"));
}
}
else
{
basket::populateForm($form);
}
$view = new Admin_View("admin.html");
$view->content = new View("admin_configure.html");
$view->content->form = $form;
print $view;
}
/**
* the index page of the user homes admin
*/
public function templates()
{
$form = basket::get_template_form();
if (request::method() == "post") {
access::verify_csrf();
if ($form->validate()) {
basket::extractTemplateForm($form);
message::success(t("Basket Module Configured!"));
}
}
else
{
basket::populateTemplateForm($form);
}
$view = new Admin_View("admin.html");
$view->content = new View("admin_templates.html");
$view->content->form = $form;
print $view;
}
public function paypal_encrypt_wizard_step1()
{
$view = new Admin_View("admin.html");
$view->content = new View("pew1.html");
$view->content->form = self::keyGenerationForm();
print $view;
}
public function paypal_encrypt_wizard_step2()
{
access::verify_csrf();
$form = self::keyGenerationForm();
if (!$form->validate()) {
self::paypal_encrypt_wizard_step1();
return;
}
$ssldir = str_replace('\\','/',VARPATH.'certificate');
$ssldir= rtrim($ssldir, '/').'/';
if ( ! is_dir($ssldir))
{
// Create the upload directory
mkdir($ssldir, 0777, TRUE);
}
$prkeyfile = $ssldir . "myprvkey.pem";
$pubcertfile = $ssldir . "mypubcert.pem";
$certreqfile = $ssldir . "mycertreq.pem";
$dn = array("countryName" => $form->encrypt->countryName->value,
"stateOrProvinceName" => $form->encrypt->stateOrProvinceName->value,
"localityName" => $form->encrypt->localityName->value,
"organizationName" => $form->encrypt->organizationName->value,
"organizationalUnitName" => $form->encrypt->organizationalUnitName->value,
"commonName" => $form->encrypt->commonName->value,
"emailAddress" => $form->encrypt->emailAddress->value);
$privkeypass = $form->encrypt->privKeyPass->value;
$numberofdays = 365;
$config = array(
"private_key_bits" => 1024
);
$privkey = openssl_pkey_new($config);
$csr = openssl_csr_new($dn, $privkey);
$sscert = openssl_csr_sign($csr, null, $privkey, $numberofdays);
openssl_x509_export($sscert, $publickey);
openssl_pkey_export($privkey, $privatekey, $privkeypass);
openssl_csr_export($csr, $csrStr);
openssl_x509_export_to_file($sscert, $pubcertfile);
openssl_pkey_export_to_file ($privkey, $prkeyfile, $privkeypass);
openssl_csr_export_to_file($csr, $certreqfile);
//echo "Your Public Certificate has been saved to " . $pubcertfile . "<br><br>";
//echo "Your Private Key has been saved to " . $prkeyfile . "<br><br>";
//echo "Your Certificate Request has been saved to " . $certreqfile . "<br><br>";
//echo $privatekey; // Will hold the exported PriKey
//echo $publickey; // Will hold the exported PubKey
//echo $csrStr; // Will hold the exported Certificate
}
private function keyGenerationForm()
{
$form = new Forge("admin/configure/paypal_encrypt_wizard_step2", "", "post", array("id" => "generateKeys", "name" =>"generateKeys"));
$group = $form->group("encrypt")->label(t("Key Generation Details"));
$group->input("countryName")->label(t("Country Name"))->id("countryName");
$group->input("stateOrProvinceName")->label(t("State or Province Name"))->id("stateOrProvinceName");
$group->input("localityName")->label(t("Locality Name"))->id("localityName");
$group->input("organizationName")->label(t("Organization Name"))->id("organizationName");
$group->input("organizationalUnitName")->label(t("Organizational Unit Name"))->id("organizationalUnitName");
$group->input("commonName")->label(t("Common Name"))->id("commonName");
$group->input("emailAddress")->label(t("E-Mail Address"))->id("emailAddress");
$group->input("privKeyPass")->label(t("Private Key Pass"))->id("privkeypass");
return $form;
}
}

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -41,35 +41,34 @@ class Admin_Postage_Bands_Controller extends Controller
access::verify_csrf();
$form = postage_band::get_add_form_admin();
try {
$valid = $form->validate();
$postage_band = ORM::factory("postage_band");
$postage_band->name = $form->add_postage->inputs["name"]->value;
$postage_band->flat_rate = $form->add_postage->flat_rate->value;
$postage_band->per_item = $form->add_postage->per_item->value;
$postage_band->validate();
} catch (ORM_Validation_Exception $e) {
// Translate ORM validation errors into form error messages
foreach ($e->validation->errors() as $key => $error) {
$form->add_postage->inputs[$key]->add_error($error, 1);
}
$valid = $form->validate();
$name = $form->add_postage->inputs["name"]->value;
$postage = ORM::factory("postage_band")->where("name","=", $name)->find();
if ($postage->loaded()) {
$form->add_postage->inputs["name"]->add_error("in_use", 1);
$valid = false;
}
if ($valid) {
$postage_band->save();
$postage = postage_band::create(
$name,
$form->add_postage->flat_rate->value,
$form->add_postage->per_item->value
);
$postage->save();
message::success(t("Created postage band %postage_name", array(
"postage_name" => html::clean($postage_band->name))));
print json_encode(array("result" => "success"));
"postage_name" => html::clean($postage->name))));
print json::reply(array("result" => "success"));
} else {
print json_encode(array("result" => "error", "form" => (string)$form));
print $form;
}
}
public function delete_postage_band_form($id) {
$postage = ORM::factory("postage_band", $id);
if (!$postage->loaded()) {
throw new Kohana_404_Exception();
kohana::show_404();
}
print postage_band::get_delete_form_admin($postage);
}
@ -77,13 +76,9 @@ class Admin_Postage_Bands_Controller extends Controller
public function delete_postage_band($id) {
access::verify_csrf();
if ($id == user::active()->id || $id == user::guest()->id) {
access::forbidden();
}
$postage = ORM::factory("postage_band", $id);
if (!$postage->loaded()) {
throw new Kohana_404_Exception();
kohana::show_404();
}
$form = postage_band::get_delete_form_admin($postage);
@ -91,13 +86,13 @@ class Admin_Postage_Bands_Controller extends Controller
$name = $postage->name;
$postage->delete();
} else {
print json_encode(array("result" => "error", "form" => (string)$form));
print $form;
}
$message = t("Deleted user %postage_band", array("postage_band" => html::clean($name)));
log::success("user", $message);
message::success($message);
print json_encode(array("result" => "success"));
print json::reply(array("result" => "success"));
}
public function edit_postage_band($id) {
@ -105,38 +100,43 @@ class Admin_Postage_Bands_Controller extends Controller
$postage = ORM::factory("postage_band", $id);
if (!$postage->loaded()) {
throw new Kohana_404_Exception();
kohana::show_404();
}
$form = postage_band::get_edit_form_admin($postage);
try {
$valid = $form->validate();
$postage->name = $form->edit_postage->inputs["name"]->value;
$postage->flat_rate = $form->edit_postage->flat_rate->value;
$postage->per_item = $form->edit_postage->per_item->value;
$postage->validate();
} catch (ORM_Validation_Exception $e) {
// Translate ORM validation errors into form error messages
foreach ($e->validation->errors() as $key => $error) {
$form->edit_postage->inputs[$key]->add_error($error, 1);
$valid = $form->validate();
if ($valid) {
$new_name = $form->edit_postage->inputs["name"]->value;
if ($new_name != $postage->name &&
ORM::factory("postage_band")
->where("name", "=", $new_name)
->where("id","!=", $postage->id)
->find()
->loaded()) {
$form->edit_postage->inputs["name"]->add_error("in_use", 1);
$valid = false;
} else {
$postage->name = $new_name;
}
$valid = false;
}
if ($valid) {
$postage->flat_rate = $form->edit_postage->flat_rate->value;
$postage->per_item = $form->edit_postage->per_item->value;
$postage->save();
message::success(t("Changed postage band %postage_name",
array("postage_name" => html::clean($postage->name))));
print json_encode(array("result" => "success"));
print json::reply(array("result" => "success"));
} else {
print json_encode(array("result" => "error", "form" => (string)$form));
print $form;
}
}
public function edit_postage_band_form($id) {
$postage = ORM::factory("postage_band", $id);
if (!$postage->loaded()) {
throw new Kohana_404_Exception();
kohana::show_404();
}
$form = postage_band::get_edit_form_admin($postage);

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -41,35 +41,35 @@ class Admin_Product_Lines_Controller extends Controller
access::verify_csrf();
$form = product::get_add_form_admin();
try {
$valid = $form->validate();
$product = ORM::factory("product");
$product->name = $form->add_product->inputs["name"]->value;
$product->description = $form->add_product->description->value;
$product->postage_band_id = $form->add_product->postage_band->value;
$product->validate();
} catch (ORM_Validation_Exception $e) {
// Translate ORM validation errors into form error messages
foreach ($e->validation->errors() as $key => $error) {
$form->add_product->inputs[$key]->add_error($error, 1);
}
$valid = $form->validate();
$name = $form->add_product->inputs["name"]->value;
$product = ORM::factory("product")->where("name", "=", $name)->find();
if ($product->loaded()) {
$form->add_product->inputs["name"]->add_error("in_use", 1);
$valid = false;
}
if ($valid) {
$product = product::create(
$name,
$form->add_product->cost->value,
$form->add_product->description->value,
$form->add_product->postage_band->value
);
$product->save();
message::success(t("Created product %product_name", array(
"product_name" => html::clean($product->name))));
print json_encode(array("result" => "success"));
print json::reply(array("result" => "success"));
} else {
print json_encode(array("result" => "error", "form" => (string)$form));
print $form;
}
}
public function delete_product_form($id) {
$product = ORM::factory("product", $id);
if (!$product->loaded()) {
throw new Kohana_404_Exception();
kohana::show_404();
}
print product::get_delete_form_admin($product);
}
@ -77,13 +77,9 @@ class Admin_Product_Lines_Controller extends Controller
public function delete_product($id) {
access::verify_csrf();
if ($id == user::active()->id || $id == user::guest()->id) {
access::forbidden();
}
$product = ORM::factory("product", $id);
if (!$product->loaded()) {
throw new Kohana_404_Exception();
kohana::show_404();
}
$form = product::get_delete_form_admin($product);
@ -91,14 +87,13 @@ class Admin_Product_Lines_Controller extends Controller
$name = $product->name;
$product->delete();
} else {
print json_encode(array("result" => "error",
"form" => $form->__toString()));
print $form;
}
$message = t("Deleted user %product_name", array("product_name" => html::clean($name)));
log::success("user", $message);
message::success($message);
print json_encode(array("result" => "success"));
print json::reply(array("result" => "success"));
}
public function edit_product($id) {
@ -106,39 +101,44 @@ class Admin_Product_Lines_Controller extends Controller
$product = ORM::factory("product", $id);
if (!$product->loaded()) {
throw new Kohana_404_Exception();
kohana::show_404();
}
$form = product::get_edit_form_admin($product);
try {
$valid = $form->validate();
$product->name = $form->edit_product->inputs["name"]->value;
$product->cost = $form->edit_product->cost->value;
$product->description = $form->edit_product->description->value;
$product->postage_band_id = $form->edit_product->postage_band->value;
$product->validate();
} catch (ORM_Validation_Exception $e) {
// Translate ORM validation errors into form error messages
foreach ($e->validation->errors() as $key => $error) {
$form->edit_product->inputs[$key]->add_error($error, 1);
$valid = $form->validate();
if ($valid) {
$new_name = $form->edit_product->inputs["name"]->value;
if ($new_name != $product->name &&
ORM::factory("product")
->where("name", "=", $new_name)
->where("id","!=", $product->id)
->find()
->loaded()) {
$form->edit_product->inputs["name"]->add_error("in_use", 1);
$valid = false;
} else {
$product->name = $new_name;
}
$valid = false;
}
if ($valid) {
$product->cost = $form->edit_product->cost->value;
$product->description = $form->edit_product->description->value;
$product->postage_band_id = $form->edit_product->postage_band->value;
$product->save();
message::success(t("Changed product %product_name",
array("product_name" => html::clean($product->name))));
print json_encode(array("result" => "success"));
print json::reply(array("result" => "success"));
} else {
print json_encode(array("result" => "error", "form" => (string)$form));
print $form;
}
}
public function edit_product_form($id) {
$product = ORM::factory("product", $id);
if (!$product->loaded()) {
throw new Kohana_404_Exception();
kohana::show_404();
}
$form = product::get_edit_form_admin($product);

View File

@ -0,0 +1,443 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class Basket_Controller extends Controller {
public function temp(){
$db = Database::instance();
$db->query("ALTER TABLE {orders} ADD COLUMN `method` int(9) DEFAULT 0;");
}
public function view_basket($pp="") {
$template = new Theme_View("page.html", "basket");
$basket = Session_Basket::get();
if (isset($pp)){
if ($pp=="nopp"){
$basket->disablepp();
}
elseif ($pp=="ppon"){
$basket->enablepp();
}
}
$view = new View("view_basket.html");
$view->basket = $basket;
$template->content = $view;
print $template;
}
public function preview($id) {
$item = ORM::factory("item", $id);
print "<img src='".$item->resize_url()."'></img>";
}
public function view_orders() {
self::check_view_orders();
$template = new Theme_View("page.html", "basket");
$incomplete_orders = ORM::factory("order")->where('status',"<",20)->find_all();
$view = new View("view_orders.html");
$view->orders = $incomplete_orders;
$template->content = $view;
print $template;
}
public function view_ipn($orderid){
self::check_view_orders();
$template = new Theme_View("page.html", "basket");
$order = ORM::factory("order")->where("id","=",$orderid)->find();
$ipn_messages = ORM::factory("ipn_message")->where("key","=",$orderid)->find_all();
//$ipn_messages = ORM::factory("ipn_message")->find_all();
$view = new View("view_ipn.html");
$view->order = $order;
$view->ipn_messages = $ipn_messages;
$template->content = $view;
print $template;
}
public function check_view_orders() {
if (!basket::can_view_orders()){
die("Invalid access.");
}
}
public function print_order($id){
access::verify_csrf();
self::check_view_orders();
$prefix = basket::getOrderPrefix();
$length = strlen($prefix);
if (strlen($id)>$length ){
if ($prefix === strtolower(substr($id,0,$length ))){
$id = substr($id,$length);
}
}
$order = ORM::factory("order", $id);
$view = new View("print_order.html");
if ($order->loaded()){
$view->order = str_replace(array("\r\n", "\n", "\r"),"<br/>",$order->text);
}else{
$view->order = "Order ".$id." not found.";
}
print $view;
}
public function show_order($id){
access::verify_csrf();
self::check_view_orders();
$prefix = basket::getOrderPrefix();
$length = strlen($prefix);
if (strlen($id)>$length ){
if ($prefix === strtolower(substr($id,0,$length ))){
$id = substr($id,$length);
}
}
$order = ORM::factory("order", $id);
if ($order->loaded()){
$view = new View("view_order.html");
$view->order = $order;
print $view;
}else{
print "Order ".$id." not found.";
}
}
public function show_ipn($id){
access::verify_csrf();
self::check_view_orders();
$ipn_message = ORM::factory("ipn_message", $id);
if ($ipn_message->loaded()){
print $ipn_message->text;
}else{
print "IPN Message ".$id." not found.";
}
}
public function confirm_order_delivery($id){
access::verify_csrf();
self::check_view_orders();
$order = ORM::factory("order", $id);
if ($order->loaded()){
if ($order->status == 2)
{
$order->status = 20;
$order->save();
}
}
url::redirect("basket/view_orders");
}
public function confirm_order_payment($id){
access::verify_csrf();
self::check_view_orders();
$order = ORM::factory("order", $id);
if ($order->loaded()){
if ($order->status == 1)
{
$order->status = 2;
$order->save();
}
}
url::redirect("basket/view_orders");
}
private function getCheckoutForm(){
$form = new Forge("basket/confirm", "", "post", array("id" => "checkout", "name" =>"checkout"));
$group = $form->group("contact")->label(t("Contact Details"));
$group->input("fullname")->label(t("Name"))->id("fullname");
$group->input("house")->label(t("House Number / Name"))->id("house");
$group->input("street")->label(t("Street"))->id("street");
$group->input("suburb")->label(t("Suburb"))->id("suburb");
$group->input("town")->label(t("Town or City"))->id("town");
$group->input("postcode")->label(t("Postcode"))->id("postcode");
$group->input("email")->label(t("E-Mail Address"))->id("email");
$group->input("phone")->label(t("Telephone Number"))->id("phone");
$group->hidden("paypal")->id("paypal");
return $form;
}
public function checkout () {
$template = new Theme_View("page.html", "basket");
$view = new View("checkout.html");
$basket = Session_Basket::get();
$form = self::getCheckoutForm();
$form->contact->fullname->value($basket->name);
$form->contact->house->value($basket->house);
$form->contact->street->value($basket->street);
$form->contact->suburb->value($basket->suburb);
$form->contact->town->value($basket->town);
$form->contact->postcode->value($basket->postcode);
$form->contact->email->value($basket->email);
$form->contact->phone->value($basket->phone);
$view->form = $form;
$template->content = $view;
print $template;
}
public function confirm () {
access::verify_csrf();
$form = $this->getCheckoutForm();
$valid = $form->validate();
if ($valid){
$basket = Session_Basket::get();
if (!isset($basket->contents ) || count($basket->contents) == 0) {
self::view_basket();
return;
}
$basket->name = $form->contact->fullname->value;
$basket->house = $form->contact->house->value;
$basket->street = $form->contact->street->value;
$basket->suburb = $form->contact->suburb->value;
$basket->town = $form->contact->town->value;
$basket->postcode = $form->contact->postcode->value;
$basket->email = $form->contact->email->value;
$basket->phone = $form->contact->phone->value;
$paypal=$form->contact->paypal->value=="true";
$template = new Theme_View("page.html", "basket");
if ($paypal){
// create a prelimary order
$order = basket::createOrder($basket, Order_Model::PAYMENT_PAYPAL);
$paypal = new Paypal();
// create the order first
$view = new View("paypal_redirect.html");
$view ->form = $paypal->process($basket,
url::site("basket/paypal_complete/$order->id", "http"),
url::site("basket/paypal_cancel/$order->id", "http"),
url::site("basket/paypal_ipn/$order->id", "http"));
$template->content = $view;
print $template;
// redirect to paypal
}else
{
$form = new Forge("basket/complete", "", "post", array("id" => "confirm", "name" =>"confirm"));
$view = new View("confirm_order.html");
$view->basket = $basket;
$template->content = $view;
$view->form = $form;
print $template;
}
}
else
{
die("Invalid confirmation!");
}
}
function paypal_ipn($id){
$order = ORM::factory("order")->where("id","=",$id)->find();
if ($order->loaded()){
$paypal = new Paypal();
if ($paypal->validate_ipn($id)){
if ($paypal->ipn_data['payment_status'] == "Completed"){
$order->status = Order_Model::PAYMENT_CONFIRMED;
// send e-mails
basket::send_order($order);
basket::send_invoice($order);
$order->save();
}
return;
}
print "invalid access. tut tut!";
}
return;
}
public function paypal_complete($id) {
$order = ORM::factory("order")->where("id","=",$id)->find();
$basket = Session_Basket::get();
$basket->clear();
$this->_complete($order);
}
public function paypal_cancel($id){
$order = ORM::factory("order")->where("id","=",$id)->find();
if ($order->loaded()){
$order->delete();
}
$this->checkout();
}
public function complete () {
access::verify_csrf();
$basket = Session_Basket::get();
if (!isset($basket->contents ) || count($basket->contents) == 0) {
self::view_basket();
return;
}
// create order
$order = basket::createOrder($basket, Order_Model::PAYMENT_OFFLINE);
$basket->clear();
// send e-mails
basket::send_order($order);
basket::send_invoice($order);
$this->_complete($order);
}
private function _complete($order){
$template = new Theme_View("page.html", "basket");
$view = new View("order_complete.html");
$ordernumber = basket::getOrderPrefix().$order->id;
$view->ordernumber = $ordernumber;
$view->order = $order;
$view->total_cost = $order->cost;
$template->content = $view;
print $template;
}
private function getAddToBasketForm($id){
$form = new Forge("basket/add_to_basket", "", "post", array("id" => "gAddToBasketForm"));
$group = $form->group("add_to_basket")->label(t("Add To Basket"));
$group->hidden("id");
$group->dropdown("product")
->label(t("Product"))
->options(product::getProductArray($id));
$group->input("quantity")->label(t("Quantity"))->id("gQuantity");
$group->submit("")->value(t("Add"));
//$group->submit("proceedToCheckout")->value(t("Proceed To Checkout"));
return $form;
}
public function add_to_basket(){
access::verify_csrf();
if (!isset($_POST['id']))
{
die("no id");
}
$form = self::getAddToBasketForm($_POST['id']);
$valid = $form->validate();
if ($valid){
$basket = Session_Basket::getOrCreate();
$basket->add(
$form->add_to_basket->id->value,
$form->add_to_basket->product->value,
$form->add_to_basket->quantity->value);
$item = ORM::factory("item", $form->add_to_basket->id->value);
Session::instance()->set("redirect_home", $item->parent_id);
print json::reply(array("result" => "success"));
}
else
{
log_error("invalid form!");
}
}
public function add_to_basket_ajax($id) {
$view = new View("add_to_basket_ajax.html");
// get the item to add
$item = ORM::factory("item", $id);
if (!$item->loaded())
{
//TODO
die("Not loaded id");
}
// get the basket to add to
$form = self::getAddToBasketForm($id);
$form->add_to_basket->id->value($id);
$form->add_to_basket->quantity->value(1);
$view->form = $form;
$view->item = $item;
print $view;
}
public function remove_item($key) {
$basket = Session_Basket::getOrCreate();
$basket->remove($key);
url::redirect("basket/view_basket");
}
}

View File

@ -0,0 +1,17 @@
#basket {float:right;}
#add_to_basket {float:right}
#basketForm {max-width:200px;float:left;}
#basketThumb {float:left; padding:10px;}
#basketThumb img{max-width:100px;}
#payment {float:right; width:50%}
#checkout input,
#checkout select,
#checkout textarea {
display: block;
clear: both;
padding: .2em;
width: 100%;
}
#sidebar-basket {max-height:300px; overflow-y:auto; overflow-x:hidden;}
.order-status-1 a{color:#AA0000 !important}
.order-status-2 a{color:#00AA00 !important}

View File

@ -0,0 +1,393 @@
<?php
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class basket_Core {
static $currencies = array(
"AUD" => "Australian Dollars",
"CAD" => "Canadian Dollars",
"EUR" => "Euros",
"GBP" => "Pounds Sterling",
"JPY" => "Yen",
"USD" => "U.S. Dollars",
"NZD" => "New Zealand Dollar",
"CHF" => "Swiss Franc",
"HKD" => "Hong Kong Dollar",
"SGD" => "Singapore Dollar",
"SEK" => "Swedish Krona",
"DKK" => "Danish Krone",
"PLN" => "Polish Zloty",
"NOK" => "Norwegian Krone",
"HUF" => "Hungarian Forint",
"CZK" => "Czech Koruna",
"ILS" => "Israeli Shekel",
"MXN" => "Mexican Peso");
static $format= array(
"AUD" => "$",
"CAD" => "$",
"EUR" => "",
"GBP" => "£",
"JPY" => "¥",
"USD" => "$",
"NZD" => "$",
"CHF" => "",
"HKD" => "$",
"SGD" => "$",
"SEK" => "",
"DKK" => "",
"PLN" => "",
"NOK" => "",
"HUF" => "",
"CZK" => "",
"ILS" => "",
"MXN" => "");
static $formatweb= array(
"AUD" => "$",
"CAD" => "$",
"EUR" => "&euro;",
"GBP" => "&pound;",
"JPY" => "&yen;",
"USD" => "$",
"NZD" => "$",
"CHF" => "",
"HKD" => "$",
"SGD" => "$",
"SEK" => "",
"DKK" => "",
"PLN" => "",
"NOK" => "",
"HUF" => "",
"CZK" => "",
"ILS" => "",
"MXN" => "");
static public function can_view_orders()
{
if (identity::active_user()->admin){
return true;
}
print identity::active_user();
foreach (identity::active_user()->groups() as $group){
if ($group->name == 'shop'){
return true;
}
}
return false;
}
static function get_configure_form() {
$form = new Forge("admin/configure", "", "post", array("id" => "g-configure-form"));
$group = $form->group("configure")->label(t("Configure Basket"));
$group->input("email")->label(t("Offline Paying Email Address"))->id("g-order-email-address");
$group->dropdown("currency")
->label(t("Currency"))
->options(self::$currencies);
$group->checkbox("side_bar")->label(t("Use only side bar"))->id("g-side-bar-only");
$group->checkbox("paypal")->label(t("Use Paypal"))->id("g-paypal");
$group->input("paypal_account")->label(t("Paypal E-Mail Address"))->id("g-paypal-address");
$group->checkbox("allow_pickup")->label(t("Allow Product Pickup"))->id("g-allow-pickup");
$group->input("order_prefix")->label(t("Order Number Prefix"))->id("g-order-prefix");
$group->submit("")->value(t("Save"));
return $form;
}
static function get_template_form() {
$form = new Forge("admin/configure/templates", "", "post", array("id" => "g-configure-form"));
$group = $form->group("configure")->label(t("Configure Basket"));
$group->textarea("payment_details")->label(t("Payment Details Description"))->id("g-payment-details");
$group->textarea("order_complete_page")->label(t("Order Complete Page"))->id("g-order-complete_page");
$group->input("order_complete_email_subject")->label(t("Order Complete Email Subject"))->id("g-order-complete_email_subject");
$group->textarea("order_complete_email")->label(t("Order Complete Email"))->id("g-order-complete_email");
$group->submit("")->value(t("Save"));
return $form;
}
static function populateForm($form){
$form->configure->email->value(basket::getEmailAddress());
$form->configure->side_bar->checked(basket::is_side_bar_only());
$form->configure->paypal->checked(basket::isPaypal());
$form->configure->paypal_account->value(basket::getPaypalAccount());
$form->configure->currency->selected(basket::getCurrency());
$form->configure->allow_pickup->checked(basket::isAllowPickup());
$form->configure->order_prefix->value(basket::getOrderPrefix());
}
static function populateTemplateForm($form){
$form->configure->payment_details->value(basket::getPaymentDetails());
$form->configure->order_complete_page->value(basket::getOrderCompletePage());
$form->configure->order_complete_email_subject->value(basket::getOrderCompleteEmailSubject());
$form->configure->order_complete_email->value(basket::getOrderCompleteEmail());
}
static function extractForm($form){
$email = $form->configure->email->value;
$is_side_bar = $form->configure->side_bar->value;
$isPaypal = $form->configure->paypal->value;
$paypal_account = $form->configure->paypal_account->value;
$currency = $form->configure->currency->selected;
$allow_pickup = $form->configure->allow_pickup->value;
$order_prefix = $form->configure->order_prefix->value;
basket::setEmailAddress($email);
basket::set_side_bar_only($is_side_bar);
basket::setPaypal($isPaypal);
basket::setPaypalAccount($paypal_account);
basket::setCurrency($currency);
basket::setAllowPickup($allow_pickup);
basket::setOrderPrefix($order_prefix);
}
static function extractTemplateForm($form){
$payment_details = $form->configure->payment_details->value;
$order_complete_page = $form->configure->order_complete_page->value;
$order_complete_email_subject = $form->configure->order_complete_email_subject->value;
$order_complete_email = $form->configure->order_complete_email->value;
basket::setPaymentDetails($payment_details);
basket::setOrderCompletePage($order_complete_page);
basket::setOrderCompleteEmailSubject($order_complete_email_subject);
basket::setOrderCompleteEmail($order_complete_email);
}
static public function is_side_bar_only()
{
return module::get_var("basket","is_side_bar_only");
}
static public function set_side_bar_only($value)
{
module::set_var("basket","is_side_bar_only",$value);
}
static function getEmailAddress(){
return module::get_var("basket","email");
}
static function isPaypal(){
return module::get_var("basket","paypal");
}
static function getPaypalAccount(){
return module::get_var("basket","paypal_account");
}
static function getCurrency(){
$cur = module::get_var("basket","currency");
if (!isset($cur))
{
$cur = "USD";
}
return $cur;
}
static function getPaymentDetails(){
return module::get_var("basket","payment_details");
}
static function getOrderPrefix(){
return module::get_var("basket","order_prefix");
}
static function isAllowPickup(){
return module::get_var("basket","allow_pickup");
}
static function getOrderCompletePage(){
return module::get_var("basket","order_complete_page");
}
static function getOrderCompleteEmail(){
return module::get_var("basket","order_complete_email");
}
static function getOrderCompleteEmailSubject(){
return module::get_var("basket","order_complete_email_subject");
}
static function formatMoney($money){
return self::$format[self::getCurrency()].number_format($money,2);
}
static function formatMoneyForWeb($money){
return self::$formatweb[self::getCurrency()].number_format($money,2);
}
static function replaceStrings($string, $key_values) {
// Replace x_y before replacing x.
krsort($key_values, SORT_STRING);
$keys = array();
$values = array();
foreach ($key_values as $key => $value) {
$keys[] = "%$key";
$values[] = $value;
}
return str_replace($keys, $values, $string);
}
static function setEmailAddress($email){
module::set_var("basket","email",$email);
}
static function setPaypal($paypal){
module::set_var("basket","paypal",$paypal);
}
static function setPaypalAccount($paypal_account){
module::set_var("basket","paypal_account",$paypal_account);
}
static function setCurrency($currency){
module::set_var("basket","currency",$currency);
}
static function setPaymentDetails($details){
module::set_var("basket","payment_details",$details);
}
static function setAllowPickup($allow_pickup){
module::set_var("basket","allow_pickup",$allow_pickup);
}
static function setOrderPrefix($order_prefix){
module::set_var("basket","order_prefix",strtolower($order_prefix));
}
static function setOrderCompletePage($details){
module::set_var("basket","order_complete_page",$details);
}
static function setOrderCompleteEmail($details){
module::set_var("basket","order_complete_email",$details);
}
static function setOrderCompleteEmailSubject($details){
module::set_var("basket","order_complete_email_subject",$details);
}
static function createOrder($basket, $method){
$order = ORM::factory("order");
$order->text = "processing";
$order->save();
$ordernumber = basket::getOrderPrefix().$order->id;
//$admin_address = basket::getEmailAddress();
$postage = $basket->postage_cost();
$product_cost = $basket->cost();
$ppon = $basket->ispp();
$text = "
Order Number : ".$ordernumber."
for :
".$basket->name."
".$basket->house."
".$basket->street."
".$basket->suburb."
".$basket->town."
".$basket->postcode."
".$basket->email."
".$basket->phone."
Placed at ".date("d F Y - H:i" ,time())."
Cost of Ordered Products = ".$product_cost;
if ($ppon){
$text = $text."
Postage and Packaging Costs + ".$postage."
Total Owed ".($product_cost+$postage)." Total in ".basket::getCurrency();
}
else{
$text = $text."
Person has chosen to pick up product.
Total Owed ".($product_cost)." Total in ".basket::getCurrency();
}
$text = $text."
Items Ordered:
";
// create the order items
foreach ($basket->contents as $basket_item){
$item = $basket_item->getItem();
$prod = ORM::factory("product", $basket_item->product);
$text = $text."
".$item->title." - ".$item->url()."
".$prod->name." - ".$prod->description."
".$basket_item->quantity." @ ".$prod->cost."
";
}
if ($ppon){
$total_cost = ($product_cost+$postage);
}
else{
$total_cost = $product_cost;
}
$order->name = $basket->name;
$order->email = $basket->email;
$order->cost = $total_cost;
$order->text = $text;
$order->status = Order_Model::WAITING_PAYMENT;
$order->method = $method;
$order->save();
//$basket->clear();
return $order;
}
public function send_order($order){
$from = "From: ".basket::getEmailAddress();
$ordernumber = basket::getOrderPrefix().$order->id;
mail(basket::getEmailAddress(), "Order ".$ordernumber." from ".$order->name, $order->text, $from);
}
public function send_invoice($order)
{
$from = "From: ".basket::getEmailAddress();
$ordernumber = basket::getOrderPrefix().$order->id;
$invoice_email = basket::replaceStrings(basket::getOrderCompleteEmail(),Array(
"name"=>$order->name,
"order_number"=> $ordernumber,
"total_cost" =>basket::formatMoney($order->cost),
"order_details"=>$order->text));
mail($order->email,
basket::replaceStrings(basket::getOrderCompleteEmailSubject(),Array("order_number"=>$ordernumber)),
$invoice_email, $from);
}
}

View File

@ -0,0 +1,21 @@
<?php defined("SYSPATH") or die("No direct script access.");
class basket_block_Core {
static function get_site_list() {
return array("shopping" => t("Basket"));
}
static function get($block_id, $theme) {
$block = "";
switch ($block_id) {
case "shopping":
$block = new Block();
$block->css_id = "g-view-basket";
$block->title = t("Basket");
$block->content = new View("basket-side-bar.html");
$block->content->basket = Session_Basket::get();
break;
}
return $block;
}
}

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -34,6 +34,11 @@ class basket_event_Core{
->label(t("Configure"))
->url(url::site("admin/configure")));
$basket_menu->append(
Menu::factory("link")
->id("templates")
->label(t("Templates"))
->url(url::site("admin/configure/templates")));
$basket_menu->append(
Menu::factory("link")
->id("product_line")
->label(t("Product Lines"))
@ -43,6 +48,11 @@ class basket_event_Core{
->id("postage_bands")
->label(t("Postage Bands"))
->url(url::site("admin/postage_bands")));
$basket_menu->append(
Menu::factory("link")
->id("view_orders")
->label(t("View Orders"))
->url(url::site("basket/view_orders")));
}
@ -65,8 +75,8 @@ class basket_event_Core{
if ($product_override->loaded()){
$item_product = ORM::factory("item_product")
->where('product_override_id', "=", $product_override->id)
->where('product_id', "=", $product->id)->find();
->where('product_override_id', "=", $product_override->id)
->where('product_id', "=", $product->id)->find();
if ($item_product->loaded()){
$checked = $item_product->include;
if ($item_product->cost != -1){

View File

@ -0,0 +1,225 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class basket_installer
{
static function install(){
$db = Database::instance();
$db->query("CREATE TABLE IF NOT EXISTS {products} (
`id` int(9) NOT NULL auto_increment,
`name` TEXT NOT NULL,
`cost` DECIMAL(10,2) default 0,
`description` varchar(1024),
`postage_band_id` int(9) default 1,
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE IF NOT EXISTS {product_overrides} (
`id` int(9) NOT NULL auto_increment,
`item_id` int(9) NOT NULL,
`none` BOOLEAN default false,
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE IF NOT EXISTS {item_products} (
`id` int(9) NOT NULL auto_increment,
`product_override_id` int(9) NOT NULL,
`product_id` int(9) NOT NULL,
`include` BOOLEAN default false,
`cost` DECIMAL(10,2) default -1,
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE IF NOT EXISTS {postage_bands} (
`id` int(9) NOT NULL auto_increment,
`name` TEXT NOT NULL,
`flat_rate` DECIMAL(10,2) default 0,
`per_item` DECIMAL(10,2) default 0,
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE IF NOT EXISTS {orders} (
`id` int(9) NOT NULL auto_increment,
`status` int(9) DEFAULT 0,
`name` varchar(1024),
`email` varchar(1024),
`cost` DECIMAL(10,2) default 0,
`method` int(9) DEFAULT 0,
`text` TEXT NOT NULL,
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE IF NOT EXISTS {ipn_messages} (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`date` int(11) NOT NULL,
`key` varchar(20) NOT NULL,
`txn_id` varchar(20) NOT NULL,
`status` varchar(20) NOT NULL,
`success` bool default false,
`text` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
postage_band::create("No Postage",0,0);
product::create("4x6",5,"4\"x6\" print",1);
product::create("8x10",25,"8\"x10\" print",1);
product::create("8x12",30,"8\"x12\" print",1);
basket::setPaymentDetails(
"<p>Use the following options to pay for this order.</p>
<p>Send a chequre to..</p>
<p>Visit the shop..</p>
<p>By using internet banking..</p>"
);
basket::setOrderPrefix("ORDER");
basket::setOrderCompletePage(
"<p>Your order number is %order_number. To pay for this order please either:</p>
<p> - Send a cheque for %total_cost to with reference %order_number..</p>
<p> - Visit the shop and quote the order %order_number..</p>
<p> - Transfer %total_cost using internet banking with reference %order_number..</p>
<p>Order will be processed as soon as payment is received. You should receive an e-mail with your order details shortly.</p>"
);
basket::setOrderCompleteEmail(
"Hi %name,
Thank you for your order the order details are below. To pay for this order please either:
- Send a cheque for %total_cost to with reference %order_number..
- Visit the shop and quote the order %order_number..
- Transfer %total_cost using internet banking with reference %order_number..
Order will be processed as soon as payment is received. For order pick-ups please visit..
Order Details
-------------
%order_details
Thanks");
basket::setOrderCompleteEmailSubject(
"Photography Order %order_number");
module::set_version("basket", 5);
}
static function upgrade($version) {
$db = Database::instance();
if ($version == 1) {
// fix for allowing decimel place in money
$db->query("ALTER TABLE {products} CHANGE COLUMN `cost` `cost` DECIMAL(10,2) default 0;");
$db->query("ALTER TABLE {item_products} CHANGE COLUMN `cost` `cost` DECIMAL(10,2) default -1;");
// postage bands
$db->query("ALTER TABLE {products} ADD COLUMN `postage_band_id` int(9) default 1");
$db->query("CREATE TABLE IF NOT EXISTS {postage_bands} (
`id` int(9) NOT NULL auto_increment,
`name` TEXT NOT NULL,
`flat_rate` DECIMAL(10,2) default 0,
`per_item` DECIMAL(10,2) default 0,
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
postage_band::create("No Postage",0,0);
module::set_version("basket", $version = 2);
}
if ($version == 2) {
$db->query("CREATE TABLE IF NOT EXISTS {orders} (
`id` int(9) NOT NULL auto_increment,
`text` TEXT NOT NULL,
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
basket::setPaymentDetails(
"<p>Use the following options to pay for this order.</p>
<p>Send a chequre to..</p>
<p>Visit the shop..</p>
<p>By using internet banking..</p>"
);
basket::setOrderPrefix("ORDER");
basket::setOrderCompletePage(
"<p>Your order number is %order_number. To pay for this order please either:</p>
<p> - Send a cheque for %total_cost to with reference %order_number..</p>
<p> - Visit the shop and quote the order %order_number..</p>
<p> - Transfer %total_cost using internet banking with reference %order_number..</p>
<p>Order will be processed as soon as payment is received. You should receive an e-mail with your order details shortly.</p>"
);
basket::setOrderCompleteEmail(
"Hi %name,
Thank you for your order the order details are below. To pay for this order please either:
- Send a cheque for %total_cost to with reference %order_number..
- Visit the shop and quote the order %order_number..
- Transfer %total_cost using internet banking with reference %order_number..
Order will be processed as soon as payment is received. For order pick-ups please visit..
Order Details
-------------
%order_details
Thanks");
basket::setOrderCompleteEmailSubject(
"Photography Order %order_number");
module::set_version("basket", $version = 3);
}
if ($version ==3 ){
$db->query("ALTER TABLE {orders} ADD COLUMN `status` int(9) DEFAULT 0;");
$db->query("CREATE TABLE IF NOT EXISTS {ipn_messages} (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`date` int(11) NOT NULL,
`key` varchar(20) NOT NULL,
`txn_id` varchar(20) NOT NULL,
`status` varchar(20) NOT NULL,
`success` bool default false,
`text` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
module::set_version("basket", $version = 4);
}
if ($version==4){
$db->query("ALTER TABLE {orders} ADD COLUMN `name` varchar(1024);");
$db->query("ALTER TABLE {orders} ADD COLUMN `email` varchar(1024);");
$db->query("ALTER TABLE {orders} ADD COLUMN `method` int(9) DEFAULT 0;");
$db->query("ALTER TABLE {orders} ADD COLUMN `cost` DECIMAL(10,2) default 0");
module::set_version("basket", $version = 5);
}
}
static function uninstall(){
$db = Database::instance();
$db->query("DROP TABLE IF EXISTS {products}");
$db->query("DROP TABLE IF EXISTS {product_overrides}");
$db->query("DROP TABLE IF EXISTS {item_products}");
$db->query("DROP TABLE IF EXISTS {postage_bands}");
$db->query("DROP TABLE IF EXISTS {orders}");
$db->query("DROP TABLE IF EXISTS {ipn_messages}");
}
}

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -24,10 +24,15 @@ class basket_theme_Core {
}
static function header_top($theme) {
$view = new View("basket.html");
$view->basket = Session_Basket::get();
return $view->render();
if (!basket::is_side_bar_only())
{
$view = new View("basket.html");
$view->basket = Session_Basket::get();
return $view->render();
}
return "";
}
static function admin_head($theme) {
@ -36,12 +41,15 @@ class basket_theme_Core {
}
}
static function photo_top($theme){
if ( product::isForSale($theme->item()->id)){
$view = new View("add_to_basket.html");
if (!basket::is_side_bar_only())
{
if ( product::isForSale($theme->item()->id)){
$view = new View("add_to_basket.html");
$view->item = $theme->item();
$view->item = $theme->item();
return $view->render();
return $view->render();
}
}
return "";
}

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -56,6 +56,28 @@ class postage_band_Core {
return $form;
}
/**
* Create a new postage band
*
* @param string $name
* @param string $full_name
* @param string $password
* @return User_Model
*/
static function create($name, $flatrate, $peritemcost) {
$postage = ORM::factory("postage_band")->where("name", "=", $name)->find();
if ($postage->loaded()) {
throw new Exception("@todo postage already EXISTS $name");
}
$postage->name = $name;
$postage->flat_rate = $flatrate;
$postage->per_item = $peritemcost;
$postage->save();
return $postage;
}
/**
* returns the array of postage bands
* @return an array of postage bands

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -20,28 +20,30 @@
class product_Core {
static function get_add_form_admin() {
$form = new Forge("admin/product_lines/add_product", "", "post", array("id" => "g-add-product-form"));
$form = new Forge("admin/product_lines/add_product", "", "post", array("id" => "gAddProductForm"));
$group = $form->group("add_product")->label(t("Add Product"));
$group->input("name")->label(t("Name"))->id("g-product-name")
$group->input("name")->label(t("Name"))->id("gProductName")
->error_messages("in_use", t("There is already a product with that name"));
$group->input("cost")->label(t("Cost"))->id("gCost");
$group->input("description")->label(t("Description"))->id("g-description");
$group->input("description")->label(t("Description"))->id("gDescription");
$group->dropdown("postage_band")
->label(t("Postage Band"))
->options(postage_band::getPostageArray());
$group->submit("")->value(t("Add Product"));
$product = ORM::factory("product");
return $form;
}
static function get_edit_form_admin($product) {
$form = new Forge("admin/product_lines/edit_product/$product->id", "", "post",
array("id" => "g-edit-product-form"));
array("id" => "gEditProductForm"));
$group = $form->group("edit_product")->label(t("Edit Product"));
$group->input("name")->label(t("Name"))->id("g-product-name")->value($product->name);
$group->input("name")->label(t("Name"))->id("gProductName")->value($product->name);
$group->inputs["name"]->error_messages(
"in_use", t("There is already a product with that name"));
$group->input("cost")->label(t("Cost"))->id("g-cost")->value($product->cost);
$group->input("description")->label(t("Description"))->id("g-description")->
$group->input("cost")->label(t("Cost"))->id("gCost")->value($product->cost);
$group->input("description")->label(t("Description"))->id("gDescription")->
value($product->description);
$group->dropdown("postage_band")
->label(t("Postage Band"))
@ -55,17 +57,39 @@ class product_Core {
static function get_delete_form_admin($product) {
$form = new Forge("admin/product_lines/delete_product/$product->id", "", "post",
array("id" => "g-delete-product-form"));
array("id" => "gDeleteProductForm"));
$group = $form->group("delete_product")->label(
t("Are you sure you want to delete product %name?", array("name" => $product->name)));
$group->submit("")->value(t("Delete product %name", array("name" => $product->name)));
return $form;
}
/**
* Create a new product
*
* @param string $name
* @param string $full_name
* @param string $password
* @return User_Model
*/
static function create($name, $cost, $description, $postage_band) {
$product = ORM::factory("product")->where("name", "=", $name)->find();
if ($product->loaded()) {
throw new Exception("@todo USER_ALREADY_EXISTS $name");
}
$product->name = $name;
$product->cost = $cost;
$product->description = $description;
$product->postage_band_id = $postage_band;
$product->save();
return $product;
}
static function getProductArray($id){
$producta = array();
// check for product override
$product_override = ORM::factory("product_override")->where('item_id', "=", $id)->find();
$product_override = ORM::factory("product_override")->where('item_id', "=", $id)->find();
if (!$product_override->loaded()){
// no override found so check parents
@ -75,11 +99,12 @@ class product_Core {
$parents = $item->parents();
foreach ($parents as $parent){
// check for product override
$product_override = ORM::factory("product_override")->where('item_id', "=", $parent->id)->find();
if ($product_override->loaded()){
break;
$temp_override = ORM::factory("product_override")->where('item_id', "=", $parent->id)->find();
if ($temp_override ->loaded()){
$product_override = $temp_override;
//break;
}
}
}
}
$products = ORM::factory("product")->find_all();
@ -89,8 +114,8 @@ class product_Core {
if ($product_override->loaded()){
$show = !$product_override->none;
$item_product = ORM::factory("item_product")
->where('product_override_id', "=", $product_override->id)
->where('product_id', "=", $product->id)->find();
->where('product_override_id', "=", $product_override->id)
->where('product_id', "=", $product->id)->find();
if ($item_product->loaded()){
$cost = $item_product->cost;
@ -102,7 +127,7 @@ class product_Core {
if ($show)
{
$producta[$product->id] = $product->description." (".basket::formatMoney($cost).")";
$producta[$product->id] = html::clean($product->description)." (".basket::formatMoneyForWeb($cost).")";
}
}
@ -111,6 +136,8 @@ class product_Core {
static function isForSale($id){
try
{
// check for product override
$product_override = ORM::factory("product_override")->where('item_id', "=", $id)->find();
@ -122,9 +149,10 @@ class product_Core {
$parents = $item->parents();
foreach ($parents as $parent){
// check for product override
$product_override = ORM::factory("product_override")->where('item_id', "=", $parent->id)->find();
if ($product_override->loaded()){
break;
$temp_override = ORM::factory("product_override")->where('item_id', "=", $parent->id)->find();
if ($temp_override ->loaded()){
$product_override = $temp_override;
//break;
}
}
}
@ -136,8 +164,8 @@ class product_Core {
foreach ($products as $product){
$item_product = ORM::factory("item_product")
->where('product_override_id', "=", $product_override->id)
->where('product_id', "=", $product->id)->find();
->where('product_override_id', "=", $product_override->id)
->where('product_id', "=", $product->id)->find();
if ($item_product->loaded()){
@ -152,5 +180,10 @@ class product_Core {
} else {
return count($products) > 0;
}
}
catch (Exception $e)
{
echo $e;
}
}
}

View File

Before

Width:  |  Height:  |  Size: 424 B

After

Width:  |  Height:  |  Size: 424 B

View File

@ -0,0 +1,330 @@
<?php
/*******************************************************************************
* PHP Paypal IPN Integration Class
*******************************************************************************
* Author: Micah Carrick
* Email: email@micahcarrick.com
* Website: http://www.micahcarrick.com
*
* File: paypal.class.php
* Version: 1.3.0
* Copyright: (c) 2005 - Micah Carrick
* You are free to use, distribute, and modify this software
* under the terms of the GNU General Public License. See the
* included license.txt file.
*
*******************************************************************************
* VERION HISTORY:
* v1.3.0 [10.10.2005] - Fixed it so that single quotes are handled the
* right way rather than simple stripping them. This
* was needed because the user could still put in
* quotes.
*
* v1.2.1 [06.05.2005] - Fixed typo from previous fix :)
*
* v1.2.0 [05.31.2005] - Added the optional ability to remove all quotes
* from the paypal posts. The IPN will come back
* invalid sometimes when quotes are used in certian
* fields.
*
* v1.1.0 [05.15.2005] - Revised the form output in the submit_paypal_post
* method to allow non-javascript capable browsers
* to provide a means of manual form submission.
*
* v1.0.0 [04.16.2005] - Initial Version
*
*******************************************************************************
* DESCRIPTION:
*
* NOTE: See www.micahcarrick.com for the most recent version of this class
* along with any applicable sample files and other documentaion.
*
* This file provides a neat and simple method to interface with paypal and
* The paypal Instant Payment Notification (IPN) interface. This file is
* NOT intended to make the paypal integration "plug 'n' play". It still
* requires the developer (that should be you) to understand the paypal
* process and know the variables you want/need to pass to paypal to
* achieve what you want.
*
* This class handles the submission of an order to paypal aswell as the
* processing an Instant Payment Notification.
*
* This code is based on that of the php-toolkit from paypal. I've taken
* the basic principals and put it in to a class so that it is a little
* easier--at least for me--to use. The php-toolkit can be downloaded from
* http://sourceforge.net/projects/paypal.
*
* To submit an order to paypal, have your order form POST to a file with:
*
* $p = new paypal_class;
* $p->add_field('business', 'somebody@domain.com');
* $p->add_field('first_name', $_POST['first_name']);
* ... (add all your fields in the same manor)
* $p->submit_paypal_post();
*
* To process an IPN, have your IPN processing file contain:
*
* $p = new paypal_class;
* if ($p->validate_ipn()) {
* ... (IPN is verified. Details are in the ipn_data() array)
* }
*
*
* In case you are new to paypal, here is some information to help you:
*
* 1. Download and read the Merchant User Manual and Integration Guide from
* http://www.paypal.com/en_US/pdf/integration_guide.pdf. This gives
* you all the information you need including the fields you can pass to
* paypal (using add_field() with this class) aswell as all the fields
* that are returned in an IPN post (stored in the ipn_data() array in
* this class). It also diagrams the entire transaction process.
*
* 2. Create a "sandbox" account for a buyer and a seller. This is just
* a test account(s) that allow you to test your site from both the
* seller and buyer perspective. The instructions for this is available
* at https://developer.paypal.com/ as well as a great forum where you
* can ask all your paypal integration questions. Make sure you follow
* all the directions in setting up a sandbox test environment, including
* the addition of fake bank accounts and credit cards.
*
*******************************************************************************
*/
class Paypal_Core {
var $last_error; // holds the last error encountered
var $ipn_response; // holds the IPN response from paypal
public $ipn_data = array(); // array contains the POST values for IPN
var $fields = array(); // array holds the fields to submit to paypal
public function __construct()
{
// initialization constructor. Called when class is created.
// sandbox paypal
//$this->paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
//$this->secure_url = "ssl://www.sandbox.paypal.com";
// normal paypal
$this->paypal_url = "https://www.paypal.com/cgi-bin/webscr";
$this->secure_url = "ssl://www.paypal.com";
$this->last_error = '';
//$this->ipn_log_file = Kohana::log_directory().Kohana::config('paypal.ipn_logfile');
//$this->ipn_log = true;
$this->ipn_response = '';
// populate $fields array with a few default values. See the paypal
// documentation for a list of fields and their data types. These defaul
// values can be overwritten by the calling script.
}
function add_field($field, $value) {
// adds a key=>value pair to the fields array, which is what will be
// sent to paypal as POST variables. If the value is already in the
// array, it will be overwritten.
$this->fields["$field"] = $value;
}
public function process($session_basket, $return_url, $cancel_url, $notify_url){
$this->add_field('rm','2');
$this->add_field('cmd','_cart');
$this->add_field('upload','1');
$this->add_field('currency_code', basket::getCurrency());
$this->add_field('business', basket::getPaypalAccount());
// IPN stuff
$this->add_field('return', $return_url);
$this->add_field('cancel_return', $cancel_url);
$this->add_field('notify_url', $notify_url);
// postage
if ($session_basket->ispp()){
$postage = $session_basket->postage_cost();
if ($postage > 0) {
$this->add_field('shipping_1',$postage);
}
}
// basket contents
$id = 1;
foreach ($session_basket->contents as $key => $basket_item){
$this->add_field("item_name_$id", $basket_item->getCode());
$this->add_field("amount_$id", $basket_item->cost_per);
$this->add_field("quantity_$id",$basket_item->quantity);
$id++;
}
// shipping address
$this->add_field("payer_email", $session_basket->email);
$this->add_field("address_name", $session_basket->name);
$this->add_field("address_street", $session_basket->house." ".$session_basket->street);
$this->add_field("address_city", $session_basket->town);
$this->add_field("address_zip", $session_basket->postcode);
$this->add_field("contact_phone", $session_basket->phone);
$string = "<form method=\"post\" name=\"paypal_form\" "
."action=\"".$this->paypal_url."\">\n";
foreach ($this->fields as $name => $value) {
$string = $string."<input type=\"hidden\" name=\"$name\" value=\"$value\"/>\n";
}
$string = $string."</form><script>function s_f(){document.forms[\"paypal_form\"].submit();}; window.setTimeout(s_f,20);</script>";
return $string;
}
function validate_ipn($key) {
// parse the paypal URL
$url_parsed=parse_url($this->paypal_url);
// generate the post string from the _POST vars aswell as load the
// _POST vars into an arry so we can play with them from the calling
// script.
$post_string = 'cmd=_notify-validate';
foreach ($_POST as $field=>$value) {
$this->ipn_data["$field"] = $value;
$value = urlencode(stripslashes($value));
$value = preg_replace('/(.*[^%^0^D])(%0A)(.*)/i','${1}%0D%0A${3}',$value);
$post_string .= '&'.$field.'='.$value;
}
// open the connection to paypal
$fp = fsockopen($this->secure_url,443,$err_num,$err_str,30);
if(!$fp) {
// could not open the connection. If loggin is on, the error message
// will be in the log.
$this->last_error = "fsockopen error no. $errnum: $errstr";
$this->log_ipn_results($key,false);
return false;
} else {
// Post the data back to paypal
fputs($fp, "POST ".$url_parsed['path']." HTTP/1.1\r\n");
fputs($fp, "Host: ".$url_parsed['host']."\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ".strlen($post_string)."\r\n\r\n");
//fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $post_string . "\r\n\r\n");
// loop through the response from the server and append to variable
while(!feof($fp)) {
$this->ipn_response .= fgets($fp, 1024);
}
fclose($fp); // close connection
}
if (stristr($this->ipn_response,"VERIFIED")===false)
{
// Invalid IPN transaction. Check the log for details.
$this->last_error = 'IPN Validation Failed. '.$url_parsed['host'].'\\'.$url_parsed['path'];
$this->log_ipn_results($key,false);
return false;
}
else{
// Valid IPN transaction.
// check recievers e-mail
$business = basket::getPaypalAccount();
if ($this->ipn_data['receiver_email']!=$business)
{
$this->last_error = 'receivers e-mail did not match '.$business;
$this->log_ipn_results($key,false);
return false;
}
// if confirmed check message has not been received already
if ($this->ipn_data['payment_status'] == "Completed"){
$message = ORM::factory("ipn_message")
->where('key',"=",$key)
->where('status',"=",'completed')
->where('txn_id',"=",$this->ipn_data['txn_id'])->find();
if ($message->loaded()){
$this->last_error = 'Message alread received.';
$this->log_ipn_results($key,false);
return false;
}
}
$this->log_ipn_results($key,true);
return true;
}
}
function log_ipn_results($key, $success) {
// Timestamp
$text = '['.date('m/d/Y g:i A').'] - ';
$message = ORM::factory("ipn_message");
$message->date = time();
$message->key = $key;
$message->txn_id = $this->ipn_data['txn_id'];
$message->status = $this->ipn_data['payment_status'];
$message->success = $success;
// Success or failure being logged?
if ($success) $text .= "SUCCESS!\n";
else $text .= 'FAIL: '.$this->last_error."\n";
// Log the POST variables
$text .= "IPN POST Vars from Paypal:\n";
foreach ($this->ipn_data as $key=>$value) {
$text .= "$key=$value \n";
}
// Log the response from the paypal server
$text .= "\nIPN Response from Paypal Server:\n ".$this->ipn_response;
$message->text = $text;
$message->save();
}
function dump_fields() {
// Used for debugging, this function will output all the field/value pairs
// that are currently defined in the instance of the class using the
// add_field() function.
echo "<h3>paypal_class->dump_fields() Output:</h3>";
echo "<table width=\"95%\" border=\"1\" cellpadding=\"2\" cellspacing=\"0\">
<tr>
<td bgcolor=\"black\"><b><font color=\"white\">Field Name</font></b></td>
<td bgcolor=\"black\"><b><font color=\"white\">Value</font></b></td>
</tr>";
ksort($this->fields);
foreach ($this->fields as $key => $value) {
echo "<tr><td>$key</td><td>".urldecode($value)."&nbsp;</td></tr>";
}
echo "</table><br>";
}
}

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -90,14 +90,32 @@ class Session_Basket_Core {
public $email = "";
public $phone = "";
public $ppenabled = true;
public function clear(){
if (isset($this->contents)){
foreach ($this->contents as $key => $item){
unset($this->contents[$key]);
}
}
$this->ppenabled = true;
}
public function enablepp()
{
$this->ppenabled = true;
}
public function disablepp()
{
$this->ppenabled = false;
}
public function ispp(){
return $this->ppenabled;
}
private function create_key($product, $id){
return "$product _ $id";
}
@ -116,7 +134,7 @@ class Session_Basket_Core {
$key = $this->create_key($product, $id);
if (isset($this->contents[$key])){
$this->contents[$key]->add($id, $quantity);
$this->contents[$key]->add($quantity);
}
else {
$this->contents[$key] = new basket_item($product, $id, $quantity);

View File

@ -0,0 +1,16 @@
<?php defined("SYSPATH") or die("No direct script access.");
class Ipn_message_Model extends ORM {
public function formatedTime(){
return date("D jS F H:i", $this->date);
}
public function json_encode(){
$toReturn = array(
'id' => $this->id,
'date' => $this->formatedTime(),
'text' => text::convertText($this->text));
return $toReturn;
}
}

View File

@ -1,7 +1,7 @@
d<?php defined("SYSPATH") or die("No direct script access.");
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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

View File

@ -0,0 +1,56 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class Order_Model extends ORM {
const WAITING_PAYMENT = 1;
const PAYMENT_CONFIRMED= 2;
const PAYMENT_PAYPAL = 1;
const PAYMENT_OFFLINE = 2;
public function title(){
return basket::getOrderPrefix().$this->id." ".$this->name." ".$this->status();
}
public function status(){
switch ($this->status){
case 1:
return "Waiting Payment";
case 2:
return "Payment Confirmed";
case 20:
return "Complete";
default:
return "Unknown";
}
}
public function payment_method(){
switch ($this->method){
case 1:
return "through Paypal";
case 2:
return "offline";
default:
return "Unknown";
}
}
}

View File

@ -0,0 +1,26 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class Postage_Band_Model extends ORM {
var $rules = array(
"name" => "length[1,32]");
protected $has_many=array('products');
}

View File

@ -0,0 +1,26 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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 2 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 Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class Product_Model extends ORM {
var $rules = array(
"name" => "length[1,32]",
"description" => "length[0,255]");
protected $belongs_to=array('postage_band');
}

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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

View File

@ -1,3 +1,3 @@
name = "Shopping Basket"
description = "Provides a simple shopping basket and checkout with paypal integration"
version = 2
version = 5

View File

@ -0,0 +1,5 @@
<?php defined("SYSPATH") or die("No direct script access.") ?>
<div id="add_to_basket">
<a href="<?= url::site("basket/add_to_basket_ajax/$item->id") ?>" title="<?= t("Add To basket") ?>" class="g-dialog-link">
<?= t("Add To basket") ?></a>
</div>

View File

@ -1,8 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.") ?>
<div id="g-admin-configure">
<h1> <?= t("Configure Shopping Basket") ?> </h1>
<p>
<?= t("Use this page to configure the shopping basket. If you have paypal you can use this to processs the final payments.") ?>
</p>
<?= $form ?>
<h1> <?= t("Configure Shopping Basket") ?> </h1>
<p> <?= t("Use this page to configure the shopping basket. If you have paypal you can use this to processs the final payments.") ?>
</p>
<?= $form ?>
</div>

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.")
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -21,8 +21,8 @@
<div class="gBlock">
<a href="<?= url::site("admin/postage_bands/add_postage_band_form") ?>"
class="g-dialog-link g-button-link right ui-icon-left ui-state-default ui-corner-all"
title="<?= t("Create a new Postage Band") ?>">
class="g-dialog-link g-button right ui-icon-left ui-state-default ui-corner-all"
title="<?= t("Create a new Postage Band") ?>">
<span class="ui-icon ui-icon-circle-plus"></span>
<?= t("Add a new Postage Band") ?>
</a>
@ -31,44 +31,41 @@
<?= t("Postage Bands") ?>
</h2>
<div class="gBlockContent">
<table id="gPostageAdminList">
<div class="g-block-content">
<table id="g-postage-admin-list">
<tr>
<th><?= t("Name") ?></th>
<th><?= t("Name") ?></th>
<th><?= t("Flat Rate") ?></th>
<th><?= t("Per Item") ?></th>
<th><?= t("Actions") ?></th>
</tr>
<? foreach ($postage_bands as $i => $postage_band): ?>
<tr id="gProduct-<?= $postage_band->id ?>" class="<?= text::alternate("gOddRow", "gEvenRow") ?>">
<tr id="g-product-<?= $postage_band->id ?>" class="<?= text::alternate("gOddRow", "gEvenRow") ?>">
<td id="product-<?= $postage_band->id ?>" class="core-info ">
<?= html::clean($postage_band->name) ?>
</td>
<td>
<?= basket::formatMoneyForWeb($postage_band->flat_rate) ?>
</td>
<td>
<?= basket::formatMoney($postage_band->flat_rate) ?>
</td>
<td>
<?= basket::formatMoney($postage_band->per_item) ?>
</td>
<td class="gActions">
<a href="<?= url::site("admin/postage_bands/edit_postage_band_form/$postage_band->id") ?>"
open_text="<?= t("close") ?>"
class="g-panel-link g-button-link ui-state-default ui-corner-all ui-icon-left">
<span class="ui-icon ui-icon-pencil"></span>
<?= t("edit") ?>
</a>
<td>
<?= basket::formatMoneyForWeb($postage_band->per_item) ?>
</td>
<td class="g-actions">
<a href="<?= url::site("admin/postage_bands/edit_postage_band_form/$postage_band->id") ?>"
open_text="<?= t("close") ?>"
class="g-panel-link g-button ui-state-default ui-corner-all ui-icon-left">
<span class="ui-icon ui-icon-pencil"></span><?= t("edit") ?></a>
<a href="<?= url::site("admin/postage_bands/delete_postage_band_form/$postage_band->id") ?>"
class="g-dialog-link g-button-link ui-state-default ui-corner-all ui-icon-left">
<span class="ui-icon ui-icon-trash"></span>
<?= t("delete") ?>
</a>
</td>
<a href="<?= url::site("admin/postage_bands/delete_postage_band_form/$postage_band->id") ?>"
class="g-dialog-link g-button ui-state-default ui-corner-all ui-icon-left">
<span class="ui-icon ui-icon-trash"></span><?= t("delete") ?></a>
</tr>
</td>
</tr>
<? endforeach ?>
</table>
</table>
</div>
</div>
</div>

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.")
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -21,7 +21,7 @@
<div class="g-block">
<a href="<?= url::site("admin/product_lines/add_product_form") ?>"
class="g-dialog-link g-button g-right ui-icon-left ui-state-default ui-corner-all"
class="g-dialog-link g-button right ui-icon-left ui-state-default ui-corner-all"
title="<?= t("Create a new Product") ?>">
<span class="ui-icon ui-icon-circle-plus"></span>
<?= t("Add a new Product") ?>
@ -42,12 +42,12 @@
</tr>
<? foreach ($products as $i => $product): ?>
<tr id="g-product-<?= $product->id ?>" class="<?= text::alternate("g-odd", "g-even") ?>">
<tr id="gProduct-<?= $product->id ?>" class="<?= text::alternate("gOddRow", "gEvenRow") ?>">
<td id="product-<?= $product->id ?>" class="core-info ">
<?= html::clean($product->name) ?>
</td>
<td>
<?= basket::formatMoney($product->cost) ?>
<?= basket::formatMoneyForWeb($product->cost) ?>
</td>
<td>
<?= html::clean($product->description) ?>
@ -57,11 +57,11 @@
</td>
<td>
<td class="g-actions">
<a href="<?= url::site("admin/product_lines/edit_product_form/$product->id") ?>"
open_text="<?= t("close") ?>"
class="g-panel-link g-button ui-state-default ui-corner-all ui-icon-left">
<span class="ui-icon ui-icon-pencil"></span><span class="g-button-text"><?= t("edit") ?></span></a>
<span class="ui-icon ui-icon-pencil"></span><span class="gButtonText"><?= t("edit") ?></span></a>
<a href="<?= url::site("admin/product_lines/delete_product_form/$product->id") ?>"
class="g-dialog-link g-button ui-state-default ui-corner-all ui-icon-left">

View File

@ -0,0 +1,8 @@
<?php defined("SYSPATH") or die("No direct script access.") ?>
<div id="g-admin-configure">
<h1> <?= t("Configure Templates used for Offline Payment.") ?> </h1>
<p>
<?= t("The following can be edited to control what the user see during offline payment. Please read the documentation for more information about variables you can use in the templates") ?>
</p>
<?= $form ?>
</div>

View File

@ -0,0 +1,42 @@
<?
if ($theme->page_type != 'basket'){
if (basket::can_view_orders()){
?><a class="g-button ui-icon-left ui-state-default ui-corner-all ui-state-hover" href="<?= url::site("basket/view_Orders") ?>" title="<?= t("View Orders") ?>"><span class="ui-icon ui-icon-clipboard"></span><?= t("View Orders")?></a><?
}
$item = $theme->item();
if ($item->is_photo() && product::isForSale($theme->item()->id)){
?><p>
<a class="g-dialog-link g-button ui-icon-left ui-state-default ui-corner-all ui-state-hover" href="<?= url::site("basket/add_to_basket_ajax/$item->id") ?>"
title="<?= t("Add To Basket")?>"><span class="ui-icon ui-icon-plusthick"></span><?= t("Add To Basket") ?></a></p>
<?
}
if (isset($basket) && isset($basket->contents) && ($basket->size() > 0)) {
?><div id="sidebar-basket"><table id="gBasketList"><tr><th><?= t("Product") ?></th><th><?= t("Cost") ?></th><th></th></tr><?
$total=0;
foreach ($basket->contents as $key => $prod_details){
?><tr id="" class="<?= text::alternate("gOddRow", "gEvenRow") ?>"><td id="item-<?= $prod_details->item ?>" class="core-info"><?
$item = $prod_details->getItem();
?><img src="<?= $item->thumb_url()?>" title="<?= $item->title?>" alt="<?= $item->title?>" style="max-width:90px;"/><br/>
<?= html::clean($prod_details->quantity) ?> x <?= html::clean($prod_details->product_description()) ?></td>
<td><? $total += $prod_details->cost?><?= basket::formatMoneyForWeb($prod_details->cost); ?></td>
<td class="g-actions"><a href="<?= url::site("basket/remove_item/$key") ?>" class="g-button ui-state-default ui-corner-all ui-icon-left"><span class="ui-icon ui-icon-trash"></span></a></td>
</tr><?
}
?>
<tr class="<?= text::alternate("gOddRow", "gEvenRow") ?>">
<td>Total</td><td id="total"><?= $basket->ispp()?basket::formatMoneyForWeb($total + $postage):basket::formatMoneyForWeb($total)?></td><td></td>
</tr></table></div><br/>
<p><a class="g-button right ui-icon-left ui-state-default ui-corner-all ui-state-hover" href="<?= url::site("basket/view_basket") ?>" title="<?= t("Checkout") ?>"><span class="ui-icon ui-icon-cart"></span><?= t("Checkout") ?></a></p><?
}
}

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.")
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -18,7 +18,12 @@
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
?>
<? if ($theme->page_subtype != 'basket'): ?>
<? if ($theme->page_type != 'basket'): ?>
<? if (basket::can_view_orders()): ?>
<a href="<?= url::site("basket/view_Orders") ?>"
title="<?= t("View Orders") ?>">View Orders</a>
<? endif?>
<? if (isset($basket) && isset($basket->contents) && ($basket->size() > 0)): ?>
<div id="basket">
<a href="<?= url::site("basket/view_basket") ?>"

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.")
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -41,7 +41,7 @@ function ci(v)
return true;
}
function so(){
function so(g){
var p=true;
var d=document.checkout;
if(!ci(d.fullname)){p=false;}
@ -49,16 +49,38 @@ function so(){
if(!ci(d.phone)){p=false;}
if (p)
{
d.paypal.value=g;
d.submit();
}
}
</SCRIPT>
<div class="g-block">
<?= $form ?>
<?
$payment_details = basket::getPaymentDetails();
if ($payment_details):
?>
<div class="basket-right" id="payment">
<h2>Payment Details</h2>
<p>After you have confirmed the order we will get in contact with you to arrange payment.</p>
<?= $payment_details; ?>
</div>
<? endif; ?>
<?= $form ?>
<div class="basketbuttons">
<a href="<?= url::site("basket/view_basket") ?>" class="left g-button ui-state-default ui-corner-all ui-icon-left">
<span class="ui-icon ui-icon-arrow-1-w"></span><?= t("Back to Basket") ?></a>
<a href="javascript: so()" class="g-right g-button ui-state-default ui-corner-all ui-icon-right">
<? if (basket::isPaypal()): ?>
<a href="javascript: so(true)"
class="right g-button ui-state-default ui-corner-all ui-icon-right">
<span class="ui-icon ui-icon-arrow-1-e"></span><?= t("Pay with Credit Card or Paypal") ?></a>
<a href="javascript: so(false)"
class="right g-button ui-state-default ui-corner-all ui-icon-right">
<span class="ui-icon ui-icon-arrow-1-e"></span><?= t("Pay off line") ?></a>
<? else: ?>
<a href="javascript: so(false)" class="right g-button ui-state-default ui-corner-all ui-icon-right">
<span class="ui-icon ui-icon-arrow-1-e"></span><?= t("Proceed to Confirmation") ?></a>
<? endif?>
</div>
</div>

View File

@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.")
/**
* Gallery - a web based photo album viewer and editor
* Copyright (C) 2000-2010 Bharat Mediratta
* Copyright (C) 2000-2009 Bharat Mediratta
*
* 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
@ -22,9 +22,9 @@
function so(){document.confirm.submit();}
</SCRIPT>
<?= $form ?>
<div class="g-block">
<div class="gBlock">
<h2>Basket Summary</h2>
<div class="g-block-content">
<div class="g-block-content scrollables">
<table id="g-basket-list">
<tr>
<th><?= t("Name") ?></th>
@ -33,7 +33,8 @@ function so(){document.confirm.submit();}
<th><?= t("Cost") ?></th>
</tr>
<? foreach ($basket->contents as $key => $prod_details): ?>
<tr id="" class="<?= text::alternate("g-odd", "g-even") ?>">
<tr id="" class="<?= text::alternate("gOddRow", "gEvenRow") ?>">
<td id="item-<?= $prod_details->item ?>" class="core-info ">
<? $item = $prod_details->getItem(); ?>
<div>
@ -47,19 +48,20 @@ function so(){document.confirm.submit();}
<?= html::clean($prod_details->quantity) ?>
</td>
<td>
<?= html::clean(basket::formatMoney($prod_details->cost)) ?>
<?= basket::formatMoneyForWeb($prod_details->cost) ?>
</td>
</tr>
</tr>
<? endforeach ?>
<? $postage = $basket->postage_cost();?>
<? if ($postage > 0):?>
<tr id="" class="<?= text::alternate("g-odd", "g-even") ?>">
<td></td><td></td><td>Postage and Packaging</td><td><?= html::clean(basket::formatMoney($postage))?></td><td></td>
<tr id="" class="<?= text::alternate("gOddRow", "gEvenRow") ?>">
<td></td><td></td><td <?=$basket->ispp()?"":"style=\"text-decoration:line-through\""; ?>>Postage and Packaging</td><td <?=$basket->ispp()?"":"style=\"text-decoration:line-through\""; ?>><?= basket::formatMoneyForWeb($postage)?></td>
</tr>
<? endif;?>
<tr id="" class="<?= text::alternate("g-odd", "g-even") ?>">
<td></td><td></td><td>Total Cost</td><td><?= html::clean(basket::formatMoney($basket->cost() + $postage))?></td>
<tr id="" class="<?= text::alternate("gOddRow", "gEvenRow") ?>">
<td></td><td></td><td>Total Cost</td><td><?= $basket->ispp()?basket::formatMoneyForWeb($basket->cost() + $postage):basket::formatMoneyForWeb($basket->cost()); ?></td>
</tr>
</table>
</div>
<table>
@ -78,9 +80,10 @@ E-mail : <?= $basket->email ?><br/>
Telephone : <?= $basket->phone ?>
</td></tr>
</table>
<a href="<?= url::site("basket/checkout") ?>" class="g-left g-button ui-state-default ui-corner-all ui-icon-left">
<div class="basketbuttons">
<a href="<?= url::site("basket/checkout") ?>" class="left g-button ui-state-default ui-corner-all ui-icon-left">
<span class="ui-icon ui-icon-arrow-1-w"></span><?= t("Back to Checkout") ?></a>
<a href="javascript: so()" class="g-right g-button ui-state-default ui-corner-all ui-icon-right">
<a href="javascript: so()" class="right g-button ui-state-default ui-corner-all ui-icon-right">
<span class="ui-icon ui-icon-arrow-1-e"></span><?= t("Confirm Order") ?></a>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More