diff --git a/modules/adsense/controllers/admin_adsense.php b/modules/adsense/controllers/admin_adsense.php new file mode 100644 index 00000000..13be83d8 --- /dev/null +++ b/modules/adsense/controllers/admin_adsense.php @@ -0,0 +1,57 @@ +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; + } +} + diff --git a/modules/adsense/helpers/adsense_block.php b/modules/adsense/helpers/adsense_block.php new file mode 100644 index 00000000..7c00cb45 --- /dev/null +++ b/modules/adsense/helpers/adsense_block.php @@ -0,0 +1,39 @@ + 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; + } +} \ No newline at end of file diff --git a/modules/adsense/helpers/adsense_event.php b/modules/adsense/helpers/adsense_event.php new file mode 100644 index 00000000..6611ebb1 --- /dev/null +++ b/modules/adsense/helpers/adsense_event.php @@ -0,0 +1,28 @@ +get("settings_menu") + ->append(Menu::factory("link") + ->id("adsense_menu") + ->label(t("Adsense")) + ->url(url::site("admin/adsense"))); + } +} diff --git a/modules/adsense/helpers/adsense_theme.php b/modules/adsense/helpers/adsense_theme.php new file mode 100644 index 00000000..97293992 --- /dev/null +++ b/modules/adsense/helpers/adsense_theme.php @@ -0,0 +1,54 @@ +' . $code . ' + '; + + 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 = ' + + '; + + return $google_code; + } + } +} diff --git a/modules/adsense/module.info b/modules/adsense/module.info new file mode 100644 index 00000000..41cc63b2 --- /dev/null +++ b/modules/adsense/module.info @@ -0,0 +1,3 @@ +name = "Adsense" +description = "Display Google Adsense ads" +version = 1 diff --git a/modules/adsense/views/admin_adsense.html.php b/modules/adsense/views/admin_adsense.html.php new file mode 100644 index 00000000..f994fae5 --- /dev/null +++ b/modules/adsense/views/admin_adsense.html.php @@ -0,0 +1,7 @@ + +
+ * 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()));
+ * }
+ * }
+ *
+ *
+ * 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);
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/modules/autorotate/lib/pel/PelConvert.php b/modules/autorotate/lib/pel/PelConvert.php
new file mode 100644
index 00000000..31c4b2a6
--- /dev/null
+++ b/modules/autorotate/lib/pel/PelConvert.php
@@ -0,0 +1,397 @@
+
+ * @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
+ * $entry = $ifd->getEntry(PelTag::IMAGE_DESCRIPTION);
+ * print($entry->getValue());
+ * $entry->setValue('This is my image. I like it.');
+ *
+ *
+ * @author Martin Geisler
+ * $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);
+ *
+ *
+ * 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
+ * $entry = new PelEntryCopyright('Copyright, Martin Geisler, 2004');
+ * $ifd0->addEntry($entry);
+ *
+ *
+ * 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
+ * $entry = $ifd->getEntry(PelTag::XP_TITLE);
+ * print($entry->getValue());
+ * $entry->setValue('My favorite cat');
+ *
+ *
+ * @author Martin Geisler
+ * $w = $ifd->getEntry(PelTag::EXIF_IMAGE_WIDTH);
+ * $w->setValue($w->getValue() / 2);
+ * $h = $ifd->getEntry(PelTag::EXIF_IMAGE_HEIGHT);
+ * $h->setValue($h->getValue() / 2);
+ *
+ * Here the width and height is updated to 50% of their original
+ * values.
+ *
+ * @author Martin Geisler
+ * $a = new PelEntryLong(PelTag::EXIF_IMAGE_WIDTH, 123456);
+ * $b = $a->getValue() - 654321;
+ *
+ * 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
+ * $resolution = $ifd->getEntry(PelTag::X_RESOLUTION);
+ * $resolution->setValue(array(1, 300));
+ *
+ *
+ * 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
+ * $w = $ifd->getEntry(PelTag::EXIF_IMAGE_WIDTH);
+ * $w->setValue($w->getValue() / 2);
+ * $h = $ifd->getEntry(PelTag::EXIF_IMAGE_HEIGHT);
+ * $h->setValue($h->getValue() / 2);
+ *
+ *
+ * Here the width and height is updated to 50% of their original
+ * values.
+ *
+ * @author Martin Geisler
+ * $a = new PelEntryShort(PelTag::EXIF_IMAGE_HEIGHT, 42);
+ * $b = $a->getValue() + 314;
+ *
+ * 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
+ * $entry = new PelEntryUserComment('An ASCII string');
+ * echo $entry->getValue();
+ *
+ *
+ * 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
+ * $entry = new PelEntryVersion(PelTag::EXIF_VERSION, 2.2);
+ *
+ * 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:
+ *
+ * if ($entry->getTag() == PelTag::EXIF_VERSION &&
+ * $entry->getValue() > 2.0) {
+ * echo 'Recent Exif version.';
+ * }
+ *
+ *
+ * @author Martin Geisler
+ * if (isset($ifd[PelTag::FNUMBER]))
+ * // ... do something with the F-number.
+ *
+ *
+ * @param PelTag the offset to check.
+ *
+ * @return boolean whether the tag exists.
+ */
+ function offsetExists($tag) {
+ return isset($this->entries[$tag]);
+ }
+
+
+ /**
+ * Retrieve a given tag from this IFD.
+ *
+ * This methods is part of the ArrayAccess SPL interface for
+ * overriding array access of objects, it allows you to read entries
+ * from the IFD the same was as for an array:
+ *
+ *
+ * $entry = $ifd[PelTag::FNUMBER];
+ *
+ *
+ * @param PelTag the tag to return. It is an error to ask for a tag
+ * which is not in the IFD, just like asking for a non-existant
+ * array entry.
+ *
+ * @return PelEntry the entry.
+ */
+ function offsetGet($tag) {
+ return $this->entries[$tag];
+ }
+
+
+ /**
+ * Set or update a given tag in this IFD.
+ *
+ * This methods is part of the ArrayAccess SPL interface for
+ * overriding array access of objects, it allows you to add new
+ * entries or replace esisting entries by doing:
+ *
+ *
+ * $ifd[PelTag::EXPOSURE_BIAS_VALUE] = $entry;
+ *
+ *
+ * Note that the actual array index passed is ignored! Instead the
+ * {@link PelTag} from the entry is used.
+ *
+ * @param PelTag the offset to update.
+ *
+ * @param PelEntry the new value.
+ */
+ function offsetSet($tag, $e) {
+ if ($e instanceof PelEntry) {
+ $tag = $e->getTag();
+ $this->entries[$tag] = $e;
+ } else {
+ throw new PelInvalidArgumentException('Argument "%s" must be a PelEntry.', $e);
+ }
+ }
+
+
+ /**
+ * Unset a given tag in this IFD.
+ *
+ * This methods is part of the ArrayAccess SPL interface for
+ * overriding array access of objects, it allows you to delete
+ * entries in the IFD by doing:
+ *
+ *
+ * unset($ifd[PelTag::EXPOSURE_BIAS_VALUE])
+ *
+ *
+ * @param PelTag the offset to delete.
+ */
+ function offsetUnset($tag) {
+ unset($this->entries[$tag]);
+ }
+
+
+ /**
+ * Retrieve an entry.
+ *
+ * @param PelTag the tag identifying the entry.
+ *
+ * @return PelEntry the entry associated with the tag, or null if no
+ * such entry exists.
+ */
+ function getEntry($tag) {
+ if (isset($this->entries[$tag]))
+ return $this->entries[$tag];
+ else
+ return null;
+ }
+
+
+ /**
+ * Returns all entries contained in this IFD.
+ *
+ * @return array an array of {@link PelEntry} objects, or rather
+ * descendant classes. The array has {@link PelTag}s as keys
+ * and the entries as values.
+ *
+ * @see getEntry
+ * @see getIterator
+ */
+ function getEntries() {
+ return $this->entries;
+ }
+
+
+ /**
+ * Return an iterator for all entries contained in this IFD.
+ *
+ * Used with foreach as in
+ *
+ *
+ * foreach ($ifd as $tag => $entry) {
+ * // $tag is now a PelTag and $entry is a PelEntry object.
+ * }
+ *
+ *
+ * @return Iterator an iterator using the {@link PelTag tags} as
+ * keys and the entries as values.
+ */
+ function getIterator() {
+ return new ArrayIterator($this->entries);
+ }
+
+
+ /**
+ * Returns available thumbnail data.
+ *
+ * @return string the bytes in the thumbnail, if any. If the IFD
+ * does not contain any thumbnail data, the empty string is
+ * returned.
+ *
+ * @todo Throw an exception instead when no data is available?
+ *
+ * @todo Return the $this->thumb_data object instead of the bytes?
+ */
+ function getThumbnailData() {
+ if ($this->thumb_data != null)
+ return $this->thumb_data->getBytes();
+ else
+ return '';
+ }
+
+
+ /**
+ * Make this directory point to a new directory.
+ *
+ * @param PelIfd the IFD that this directory will point to.
+ */
+ function setNextIfd(PelIfd $i) {
+ $this->next = $i;
+ }
+
+
+ /**
+ * Return the IFD pointed to by this directory.
+ *
+ * @return PelIfd the next IFD, following this IFD. If this is the
+ * last IFD, null is returned.
+ */
+ function getNextIfd() {
+ return $this->next;
+ }
+
+
+ /**
+ * Check if this is the last IFD.
+ *
+ * @return boolean true if there are no following IFD, false
+ * otherwise.
+ */
+ function isLastIfd() {
+ return $this->next == null;
+ }
+
+
+ /**
+ * Add a sub-IFD.
+ *
+ * Any previous sub-IFD of the same type will be overwritten.
+ *
+ * @param PelIfd the sub IFD. The type of must be one of {@link
+ * PelIfd::EXIF}, {@link PelIfd::GPS}, or {@link
+ * PelIfd::INTEROPERABILITY}.
+ */
+ function addSubIfd(PelIfd $sub) {
+ $this->sub[$sub->type] = $sub;
+ }
+
+
+ /**
+ * Return a sub IFD.
+ *
+ * @param int the type of the sub IFD. This must be one of {@link
+ * PelIfd::EXIF}, {@link PelIfd::GPS}, or {@link
+ * PelIfd::INTEROPERABILITY}.
+ *
+ * @return PelIfd the IFD associated with the type, or null if that
+ * sub IFD does not exist.
+ */
+ function getSubIfd($type) {
+ if (isset($this->sub[$type]))
+ return $this->sub[$type];
+ else
+ return null;
+ }
+
+
+ /**
+ * Get all sub IFDs.
+ *
+ * @return array an associative array with (IFD-type, {@link
+ * PelIfd}) pairs.
+ */
+ function getSubIfds() {
+ return $this->sub;
+ }
+
+
+ /**
+ * Turn this directory into bytes.
+ *
+ * This directory will be turned into a byte string, with the
+ * specified byte order. The offsets will be calculated from the
+ * offset given.
+ *
+ * @param int the offset of the first byte of this directory.
+ *
+ * @param PelByteOrder the byte order that should be used when
+ * turning integers into bytes. This should be one of {@link
+ * PelConvert::LITTLE_ENDIAN} and {@link PelConvert::BIG_ENDIAN}.
+ */
+ function getBytes($offset, $order) {
+ $bytes = '';
+ $extra_bytes = '';
+
+ Pel::debug('Bytes from IDF will start at offset %d within Exif data',
+ $offset);
+
+ $n = count($this->entries) + count($this->sub);
+ if ($this->thumb_data != null) {
+ /* We need two extra entries for the thumbnail offset and
+ * length. */
+ $n += 2;
+ }
+
+ $bytes .= PelConvert::shortToBytes($n, $order);
+
+ /* Initialize offset of extra data. This included the bytes
+ * preceding this IFD, the bytes needed for the count of entries,
+ * the entries themselves (and sub entries), the extra data in the
+ * entries, and the IFD link.
+ */
+ $end = $offset + 2 + 12 * $n + 4;
+
+ foreach ($this->entries as $tag => $entry) {
+ /* Each entry is 12 bytes long. */
+ $bytes .= PelConvert::shortToBytes($entry->getTag(), $order);
+ $bytes .= PelConvert::shortToBytes($entry->getFormat(), $order);
+ $bytes .= PelConvert::longToBytes($entry->getComponents(), $order);
+
+ /*
+ * Size? If bigger than 4 bytes, the actual data is not in
+ * the entry but somewhere else.
+ */
+ $data = $entry->getBytes($order);
+ $s = strlen($data);
+ if ($s > 4) {
+ Pel::debug('Data size %d too big, storing at offset %d instead.',
+ $s, $end);
+ $bytes .= PelConvert::longToBytes($end, $order);
+ $extra_bytes .= $data;
+ $end += $s;
+ } else {
+ Pel::debug('Data size %d fits.', $s);
+ /* Copy data directly, pad with NULL bytes as necessary to
+ * fill out the four bytes available.*/
+ $bytes .= $data . str_repeat(chr(0), 4 - $s);
+ }
+ }
+
+ if ($this->thumb_data != null) {
+ Pel::debug('Appending %d bytes of thumbnail data at %d',
+ $this->thumb_data->getSize(), $end);
+ // TODO: make PelEntry a class that can be constructed with
+ // arguments corresponding to the newt four lines.
+ $bytes .= PelConvert::shortToBytes(PelTag::JPEG_INTERCHANGE_FORMAT_LENGTH,
+ $order);
+ $bytes .= PelConvert::shortToBytes(PelFormat::LONG, $order);
+ $bytes .= PelConvert::longToBytes(1, $order);
+ $bytes .= PelConvert::longToBytes($this->thumb_data->getSize(),
+ $order);
+
+ $bytes .= PelConvert::shortToBytes(PelTag::JPEG_INTERCHANGE_FORMAT,
+ $order);
+ $bytes .= PelConvert::shortToBytes(PelFormat::LONG, $order);
+ $bytes .= PelConvert::longToBytes(1, $order);
+ $bytes .= PelConvert::longToBytes($end, $order);
+
+ $extra_bytes .= $this->thumb_data->getBytes();
+ $end += $this->thumb_data->getSize();
+ }
+
+
+ /* Find bytes from sub IFDs. */
+ $sub_bytes = '';
+ foreach ($this->sub as $type => $sub) {
+ if ($type == PelIfd::EXIF)
+ $tag = PelTag::EXIF_IFD_POINTER;
+ elseif ($type == PelIfd::GPS)
+ $tag = PelTag::GPS_INFO_IFD_POINTER;
+ elseif ($type == PelIfd::INTEROPERABILITY)
+ $tag = PelTag::INTEROPERABILITY_IFD_POINTER;
+
+ /* Make an aditional entry with the pointer. */
+ $bytes .= PelConvert::shortToBytes($tag, $order);
+ /* Next the format, which is always unsigned long. */
+ $bytes .= PelConvert::shortToBytes(PelFormat::LONG, $order);
+ /* There is only one component. */
+ $bytes .= PelConvert::longToBytes(1, $order);
+
+ $data = $sub->getBytes($end, $order);
+ $s = strlen($data);
+ $sub_bytes .= $data;
+
+ $bytes .= PelConvert::longToBytes($end, $order);
+ $end += $s;
+ }
+
+ /* Make link to next IFD, if any*/
+ if ($this->isLastIFD()) {
+ $link = 0;
+ } else {
+ $link = $end;
+ }
+
+ Pel::debug('Link to next IFD: %d', $link);
+
+ $bytes .= PelConvert::longtoBytes($link, $order);
+
+ $bytes .= $extra_bytes . $sub_bytes;
+
+ if (!$this->isLastIfd())
+ $bytes .= $this->next->getBytes($end, $order);
+
+ return $bytes;
+ }
+
+
+ /**
+ * Turn this directory into text.
+ *
+ * @return string information about the directory, mainly for
+ * debugging.
+ */
+ function __toString() {
+ $str = Pel::fmt("Dumping IFD %s with %d entries...\n",
+ $this->getName(), count($this->entries));
+
+ foreach ($this->entries as $entry)
+ $str .= $entry->__toString();
+
+ $str .= Pel::fmt("Dumping %d sub IFDs...\n", count($this->sub));
+
+ foreach ($this->sub as $type => $ifd)
+ $str .= $ifd->__toString();
+
+ if ($this->next != null)
+ $str .= $this->next->__toString();
+
+ return $str;
+ }
+
+
+}
+
+?>
\ No newline at end of file
diff --git a/modules/autorotate/lib/pel/PelJpeg.php b/modules/autorotate/lib/pel/PelJpeg.php
new file mode 100644
index 00000000..f1fb0a7c
--- /dev/null
+++ b/modules/autorotate/lib/pel/PelJpeg.php
@@ -0,0 +1,599 @@
+
+ * @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
+ * $jpeg = new PelJpeg($filename);
+ * $exif = $jpeg->getExif();
+ * $tiff = $exif->getTiff();
+ * $ifd0 = $tiff->getIfd();
+ * $exif = $ifd0->getSubIfd(PelIfd::EXIF);
+ * $ifd1 = $ifd0->getNextIfd();
+ *
+ *
+ * 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
+ * $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);
+ *
+ */
+ 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:
+ *
+ *
+ * $dht3 = $jpeg->getSection(PelJpegMarker::DHT, 2);
+ *
+ *
+ * @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:
+ *
+ *
+ * foreach ($jpeg->getSections() as $section) {
+ * $marker = $section[0];
+ * $content = $section[1];
+ * // Use $marker and $content here.
+ * }
+ *
+ *
+ * instead of this:
+ *
+ *
+ * foreach ($jpeg->getSections() as $marker => $content) {
+ * // Does not work the way you would think...
+ * }
+ *
+ *
+ * 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;
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/modules/autorotate/lib/pel/PelJpegComment.php b/modules/autorotate/lib/pel/PelJpegComment.php
new file mode 100644
index 00000000..feb62c30
--- /dev/null
+++ b/modules/autorotate/lib/pel/PelJpegComment.php
@@ -0,0 +1,121 @@
+
+ * @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
+ * $tiff = new PelTiff($data);
+ * $ifd0 = $tiff->getIfd();
+ * $exif = $ifd0->getSubIfd(PelIfd::EXIF);
+ * $ifd1 = $ifd0->getNextIfd();
+ *
+ *
+ * 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 Use the following options to pay for this order.
+Send a chequre to..
+Visit the shop..
+By using internet banking..
" + ); + basket::setOrderPrefix("ORDER"); + basket::setOrderCompletePage( +"Your order number is %order_number. 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. You should receive an e-mail with your order details shortly.
" + ); + 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", 4); - module::set_version("basket", 2); } static function upgrade($version) { @@ -101,12 +140,77 @@ class basket_installer `per_item` DECIMAL(10,2) default 0, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;"); - $postage_band = ORM::factory("postage_band"); - $postage_band->name = "No Postage"; - $postage_band->save(); + 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( +"Use the following options to pay for this order.
+Send a chequre to..
+Visit the shop..
+By using internet banking..
" + ); + basket::setOrderPrefix("ORDER"); + basket::setOrderCompletePage( +"Your order number is %order_number. 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. You should receive an e-mail with your order details shortly.
" + ); + 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(){ @@ -115,5 +219,6 @@ class basket_installer $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}"); } } diff --git a/modules/basket/helpers/basket_theme.php b/modules/basket/helpers/basket_theme.php index 2c9ae671..1ad535e5 100644 --- a/modules/basket/helpers/basket_theme.php +++ b/modules/basket/helpers/basket_theme.php @@ -1,7 +1,7 @@ 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 ""; } diff --git a/modules/basket/helpers/postage_band.php b/modules/basket/helpers/postage_band.php index 042215cb..ca679d53 100644 --- a/modules/basket/helpers/postage_band.php +++ b/modules/basket/helpers/postage_band.php @@ -1,7 +1,7 @@ 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 diff --git a/modules/basket/helpers/product.php b/modules/basket/helpers/product.php index 3ac44884..a4a13c8c 100644 --- a/modules/basket/helpers/product.php +++ b/modules/basket/helpers/product.php @@ -1,7 +1,7 @@ "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; + } } } \ No newline at end of file diff --git a/modules/basket/libraries/Paypal.php b/modules/basket/libraries/Paypal.php new file mode 100644 index 00000000..c18ee058 --- /dev/null +++ b/modules/basket/libraries/Paypal.php @@ -0,0 +1,330 @@ +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 = ""; + 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 "Field Name | +Value | +
$key | ".urldecode($value)." |
- = t("Use this page to configure the shopping basket. If you have paypal you can use this to processs the final payments.") ?> -
- = $form ?> += t("Use this page to configure the shopping basket. If you have paypal you can use this to processs the final payments.") ?> +
+= $form ?>= t("Name") ?> | += t("Name") ?> | = t("Flat Rate") ?> | = t("Per Item") ?> | = t("Actions") ?> | ||
---|---|---|---|---|---|---|
= html::clean($postage_band->name) ?> + | ++ = basket::formatMoneyForWeb($postage_band->flat_rate) ?> | -- = basket::formatMoney($postage_band->flat_rate) ?> - | -- = basket::formatMoney($postage_band->per_item) ?> - | -- id") ?>" - open_text="= t("close") ?>" - class="g-panel-link g-button-link ui-state-default ui-corner-all ui-icon-left"> - - = t("edit") ?> - + | + = basket::formatMoneyForWeb($postage_band->per_item) ?> + | ++ id") ?>" + open_text="= t("close") ?>" + class="g-panel-link g-button ui-state-default ui-corner-all ui-icon-left"> + = t("edit") ?> - id") ?>" - class="g-dialog-link g-button-link ui-state-default ui-corner-all ui-icon-left"> - - = t("delete") ?> - - | + id") ?>" + class="g-dialog-link g-button ui-state-default ui-corner-all ui-icon-left"> + = t("delete") ?> -
+ = 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") ?> +
+ = $form ?> ++id") ?>" +title="= t("Add To Basket")?>">= t("Add To Basket") ?>
+ + } + + + if (isset($basket) && isset($basket->contents) && ($basket->size() > 0)) { + ?>" title="= t("Checkout") ?>">= t("Checkout") ?>
+ + } + } diff --git a/modules/basket/views/basket.html.php b/modules/basket/views/basket.html.php index ee2316ba..3a6b856b 100644 --- a/modules/basket/views/basket.html.php +++ b/modules/basket/views/basket.html.php @@ -1,7 +1,7 @@ - if ($theme->page_subtype != 'basket'): ?> + + if ($theme->page_type != 'basket'): ?> + if (basket::can_view_orders()): ?> + " + title="= t("View Orders") ?>">View Orders + endif?> if (isset($basket) && isset($basket->contents) && ($basket->size() > 0)): ?>After you have confirmed the order we will get in contact with you to arrange payment.
+= $payment_details; ?> += t("Name") ?> | @@ -33,7 +33,8 @@ function so(){document.confirm.submit();}= t("Cost") ?> | |||
---|---|---|---|---|
$item = $prod_details->getItem(); ?>
@@ -47,19 +48,20 @@ function so(){document.confirm.submit();}
= html::clean($prod_details->quantity) ?>
|
- = html::clean(basket::formatMoney($prod_details->cost)) ?> + = basket::formatMoneyForWeb($prod_details->cost) ?> | -|||
Postage and Packaging | = html::clean(basket::formatMoney($postage))?> | + | ||
ispp()?"":"style=\"text-decoration:line-through\""; ?>>Postage and Packaging | ispp()?"":"style=\"text-decoration:line-through\""; ?>>= basket::formatMoneyForWeb($postage)?> | |||
Total Cost | = html::clean(basket::formatMoney($basket->cost() + $postage))?> | +|||
Total Cost | = $basket->ispp()?basket::formatMoneyForWeb($basket->cost() + $postage):basket::formatMoneyForWeb($basket->cost()); ?> |
+ = t("The first step is to fill in some details about yourself. These details are used to create a set of encryption keys that will be used to communicate with paypal.") ?> +
+ = $form ?> + " + class="left gButtonLink ui-state-default ui-corner-all ui-icon-left"> + = t("Cancel") ?> + + " + class="right gButtonLink ui-state-default ui-corner-all ui-icon-right"> + = t("Next") ?> ++ = t("Open your paypal account on a seperate window and navigate to My account / profile / Selling Preferences - Encrypted Payment Settings.") ?> + = t("From this page press the download button to donwload paypals public certificate. Then paste the documents contents into the edit box below.") ?> +
+ = $form ?> + " + class="left gButtonLink ui-state-default ui-corner-all ui-icon-left"> + = t("Cancel") ?> + + " + class="right gButtonLink ui-state-default ui-corner-all ui-icon-right"> + = t("Next") ?> +