From d9936a9a555e6ce3c09d87930d6bb81952224179 Mon Sep 17 00:00:00 2001 From: Camil Staps Date: Wed, 20 Jul 2016 11:09:38 +0200 Subject: Reorganise classes --- classes/BusinessAdmin.class.php | 326 ------- classes/BusinessAdmin.php | 326 +++++++ classes/FPDF.php | 1804 ++++++++++++++++++++++++++++++++++++++ classes/Parsedown.class.php | 1 - classes/Parsedown.php | 1 + classes/assignment.class.php | 316 ------- classes/assignment.php | 316 +++++++ classes/client.class.php | 195 ---- classes/client.php | 195 ++++ classes/constants.class.php | 74 -- classes/constants.php | 74 ++ classes/contact.class.php | 378 -------- classes/contact.php | 378 ++++++++ classes/correspondence.class.php | 313 ------- classes/correspondence.php | 311 +++++++ classes/discount.class.php | 285 ------ classes/discount.php | 285 ++++++ classes/file.class.php | 148 ---- classes/file.php | 148 ++++ classes/fpdf.php | 1804 -------------------------------------- classes/offer.class.php | 706 --------------- classes/offer.php | 706 +++++++++++++++ classes/response.class.php | 112 --- classes/response.php | 112 +++ conf.php | 2 +- 25 files changed, 4657 insertions(+), 4659 deletions(-) delete mode 100644 classes/BusinessAdmin.class.php create mode 100644 classes/BusinessAdmin.php create mode 100644 classes/FPDF.php delete mode 120000 classes/Parsedown.class.php create mode 120000 classes/Parsedown.php delete mode 100644 classes/assignment.class.php create mode 100644 classes/assignment.php delete mode 100644 classes/client.class.php create mode 100644 classes/client.php delete mode 100644 classes/constants.class.php create mode 100644 classes/constants.php delete mode 100644 classes/contact.class.php create mode 100644 classes/contact.php delete mode 100644 classes/correspondence.class.php create mode 100644 classes/correspondence.php delete mode 100644 classes/discount.class.php create mode 100644 classes/discount.php delete mode 100644 classes/file.class.php create mode 100644 classes/file.php delete mode 100644 classes/fpdf.php delete mode 100644 classes/offer.class.php create mode 100644 classes/offer.php delete mode 100644 classes/response.class.php create mode 100644 classes/response.php diff --git a/classes/BusinessAdmin.class.php b/classes/BusinessAdmin.class.php deleted file mode 100644 index 23e9c74..0000000 --- a/classes/BusinessAdmin.class.php +++ /dev/null @@ -1,326 +0,0 @@ -. - */ - -/** - * Provides basic functions like adding elements to the database - */ -class BusinessAdmin { - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get all client ids - * - * @see BusinessAdmin::getClients() This funtion returns instances of the client class instead of just the ids - * - * @param PDO $pdo The PDO class for database connection - * - * @throws PDOException If something went wrong with the database - * - * @return int[] The ids - */ - public static function getClientIds($pdo) { - $ids = array(); - $clients = $pdo->query("SELECT `id` FROM `".constants::db_prefix."client`")->fetchAll(PDO::FETCH_ASSOC); - foreach ($clients as $client) { - $ids[] = $client['id']; - } - return $ids; - } - - /** - * Get all clients - * - * @see BusinessAdmin::getClientIds() This function returns just the ids of the clients, and not instances of the client class - * - * @param PDO $pdo The PDO class for database connection - * - * @throws PDOException If something went wrong with the database - * - * @return client[] An array indexed by id of instances of the client class - */ - public static function getClients($pdo) { - $ids = self::getClientIds($pdo); - $clients = array(); - foreach ($ids as $id) { - $clients[$id] = new client($pdo, $id); - } - return $clients; - } - - /** - * Get all contact ids - * - * @see BusinessAdmin::getContacts() This funtion returns instances of the contact class instead of just the ids - * - * @param PDO $pdo The PDO class for database connection - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public static function getContactIds($pdo) { - $ids = array(); - $contacts = $pdo->query("SELECT `id` FROM `".constants::db_prefix."contact`")->fetchAll(PDO::FETCH_ASSOC); - foreach ($contacts as $contact) { - $ids[] = $contact['id']; - } - return $ids; - } - - /** - * Get all contacts - * - * @see BusinessAdmin::getContactIds() This function returns just the ids of the contacts, and not instances of the contact class - * - * @param PDO $pdo The PDO class for database connection - * - * @throws PDOException If something went wrong with the database - * - * @return contact[] An array indexed by id of instances of the contact class - */ - public static function getContacts($pdo) { - $ids = self::getContactIds($pdo); - $contacts = array(); - foreach ($ids as $id) { - $contacts[$id] = new contact($pdo, $id); - } - return $contacts; - } - - /** - * Get all offer ids - * - * @see BusinessAdmin::getOffers() This funtion returns instances of the offer class instead of just the ids - * - * @param PDO $pdo The PDO class for database connection - * @param string[] $where An array of WHERE clauses that will be AND-ed - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public static function getOfferIds($pdo, $where = array()) { - $ids = array(); - $offers = $pdo->query("SELECT `id` FROM `".constants::db_prefix."offer`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); - foreach ($offers as $offer) { - $ids[] = $offer['id']; - } - return $ids; - } - - /** - * Get all offers - * - * @see BusinessAdmin::getOfferIds() This function returns just the ids of the offers, and not instances of the offer class - * - * @param PDO $pdo The PDO class for database connection - * @param string[] $where An array of WHERE clauses that will be AND-ed - * - * @throws PDOException If something went wrong with the database - * - * @return offer[] An array indexed by id of instances of the offer class - */ - public static function getOffers($pdo, $where = array()) { - $ids = self::getOfferIds($pdo, $where); - $offers = array(); - foreach ($ids as $id) { - $offers[$id] = new offer($pdo, $id); - } - return $offers; - } - - /** - * Get all assignment ids - * - * @see BusinessAdmin::getAssignments() This funtion returns instances of the assignment class instead of just the ids - * - * @param PDO $pdo The PDO class for database connection - * @param string[] $where An array of WHERE clauses that will be AND-ed - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public static function getAssignmentIds($pdo, $where = array()) { - $ids = array(); - $assignments = $pdo->query("SELECT `id` FROM `".constants::db_prefix."assignment`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); - foreach ($assignments as $assignment) { - $ids[] = $assignment['id']; - } - return $ids; - } - - /** - * Get all assignments - * - * @see BusinessAdmin::getAssignmentIds() This function returns just the ids of the assignments, and not instances of the assignment class - * - * @param PDO $pdo The PDO class for database connection - * @param string[] $where An array of WHERE clauses that will be AND-ed - * - * @throws PDOException If something went wrong with the database - * - * @return assignment[] An array indexed by id of instances of the assignment class - */ - public static function getAssignments($pdo, $where = array()) { - $ids = self::getAssignmentIds($pdo, $where); - $assignments = array(); - foreach ($ids as $id) { - $assignments[$id] = new assignment($pdo, $id); - } - return $assignments; - } - - /** - * Get all discount ids - * - * @see BusinessAdmin::getDiscounts() This funtion returns instances of the discount class instead of just the ids - * - * @param PDO $pdo The PDO class for database connection - * @param string[] $where An array of WHERE clauses that will be AND-ed - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public static function getDiscountIds($pdo, $where = array()) { - $ids = array(); - $discounts = $pdo->query("SELECT `id` FROM `".constants::db_prefix."discount`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); - foreach ($discounts as $discount) { - $ids[] = $discount['id']; - } - return $ids; - } - - /** - * Get all discounts - * - * @see BusinessAdmin::getDiscountIds() This function returns just the ids of the discounts, and not instances of the discount class - * - * @param PDO $pdo The PDO class for database connection - * @param string[] $where An array of WHERE clauses that will be AND-ed - * - * @throws PDOException If something went wrong with the database - * - * @return discount[] An array indexed by id of instances of the discount class - */ - public static function getDiscounts($pdo, $where = array()) { - $ids = self::getDiscountIds($pdo, $where); - $discounts = array(); - foreach ($ids as $id) { - $discounts[$id] = new discount($pdo, $id); - } - return $discounts; - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Create a new client - * - * @param PDO $pdo The database connection - * @param string $name The name for the new client - * - * @throws PDOException If something went wrong with the database - * - * @return client|bool A new instance of the client object, or false on failure - */ - public static function createClient($pdo, $name) { - $stmt = $pdo->prepare("INSERT INTO `".constants::db_prefix."client` (`name`) VALUES (?)"); - $stmt->execute(array($name)); - if ($stmt->rowCount() == 1) { - return new client($pdo, $pdo->lastInsertId()); - } else { - return false; - } - } - - /** - * Create a new file - * - * @param PDO $pdo The database connection - * @param string $filename The desired filename - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the file could not be created (due to permissions, file existed already, etc.), or the database record couldn't be added - * - * @return file A new instance of the file object - */ - public static function createFile($pdo, $filename) { - // Check for file existence - if (file_exists(constants::files_folder . $filename)) { - throw new Exception("$filename already exists."); - } - - // Try to create the file - if (file_put_contents(constants::files_folder . $filename, '') === false) { - throw new Exception("$filename could not be created. Check the permissions."); - } - - $stmt = $pdo->prepare("INSERT INTO `".constants::db_prefix."file` (`filename`) VALUES (?)"); - $stmt->execute(array($filename)); - if ($stmt->rowCount() == 1) { - return new file($pdo, $pdo->lastInsertId()); - } else { - unlink(constants::files_folder . $filename); - throw new Exception("$filename could not be added to the database"); - } - } - - /** - * Format a date nicely - * - * @todo implement $relatively = true - * - * @param int $timestamp The UNIX timestamp to format - * @param bool $with_time If false, only the date is returned; if false, also the time - * @param bool $full_date If true, a year will be outputted even if the date is in the current year - * @param bool $relatively Whether or not to show the date relatively (e.g. '1 day ago') (NOT IMPLEMENTED YET) - * - * @return string The formatted date - */ - public static function formatDate($timestamp, $with_time = true, $full_date = false, $relatively = false) { - $output = ''; - if (date('Y', $timestamp) == 1970) { - return 'never'; - } - if (date('d/m/Y') == date('d/m/Y', $timestamp)) { - return 'today'; - } - if (date('Y') != date('Y', $timestamp) || $full_date) { - $output .= date('Y-', $timestamp); - } - if (date('d/m/Y') != date('d/m/Y', $timestamp) || $full_date) { - $output .= date('m-d', $timestamp); - } - if ($with_time) { - $output .= date(' H:i', $timestamp); - } - - return $output; - } -} diff --git a/classes/BusinessAdmin.php b/classes/BusinessAdmin.php new file mode 100644 index 0000000..23e9c74 --- /dev/null +++ b/classes/BusinessAdmin.php @@ -0,0 +1,326 @@ +. + */ + +/** + * Provides basic functions like adding elements to the database + */ +class BusinessAdmin { + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get all client ids + * + * @see BusinessAdmin::getClients() This funtion returns instances of the client class instead of just the ids + * + * @param PDO $pdo The PDO class for database connection + * + * @throws PDOException If something went wrong with the database + * + * @return int[] The ids + */ + public static function getClientIds($pdo) { + $ids = array(); + $clients = $pdo->query("SELECT `id` FROM `".constants::db_prefix."client`")->fetchAll(PDO::FETCH_ASSOC); + foreach ($clients as $client) { + $ids[] = $client['id']; + } + return $ids; + } + + /** + * Get all clients + * + * @see BusinessAdmin::getClientIds() This function returns just the ids of the clients, and not instances of the client class + * + * @param PDO $pdo The PDO class for database connection + * + * @throws PDOException If something went wrong with the database + * + * @return client[] An array indexed by id of instances of the client class + */ + public static function getClients($pdo) { + $ids = self::getClientIds($pdo); + $clients = array(); + foreach ($ids as $id) { + $clients[$id] = new client($pdo, $id); + } + return $clients; + } + + /** + * Get all contact ids + * + * @see BusinessAdmin::getContacts() This funtion returns instances of the contact class instead of just the ids + * + * @param PDO $pdo The PDO class for database connection + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public static function getContactIds($pdo) { + $ids = array(); + $contacts = $pdo->query("SELECT `id` FROM `".constants::db_prefix."contact`")->fetchAll(PDO::FETCH_ASSOC); + foreach ($contacts as $contact) { + $ids[] = $contact['id']; + } + return $ids; + } + + /** + * Get all contacts + * + * @see BusinessAdmin::getContactIds() This function returns just the ids of the contacts, and not instances of the contact class + * + * @param PDO $pdo The PDO class for database connection + * + * @throws PDOException If something went wrong with the database + * + * @return contact[] An array indexed by id of instances of the contact class + */ + public static function getContacts($pdo) { + $ids = self::getContactIds($pdo); + $contacts = array(); + foreach ($ids as $id) { + $contacts[$id] = new contact($pdo, $id); + } + return $contacts; + } + + /** + * Get all offer ids + * + * @see BusinessAdmin::getOffers() This funtion returns instances of the offer class instead of just the ids + * + * @param PDO $pdo The PDO class for database connection + * @param string[] $where An array of WHERE clauses that will be AND-ed + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public static function getOfferIds($pdo, $where = array()) { + $ids = array(); + $offers = $pdo->query("SELECT `id` FROM `".constants::db_prefix."offer`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); + foreach ($offers as $offer) { + $ids[] = $offer['id']; + } + return $ids; + } + + /** + * Get all offers + * + * @see BusinessAdmin::getOfferIds() This function returns just the ids of the offers, and not instances of the offer class + * + * @param PDO $pdo The PDO class for database connection + * @param string[] $where An array of WHERE clauses that will be AND-ed + * + * @throws PDOException If something went wrong with the database + * + * @return offer[] An array indexed by id of instances of the offer class + */ + public static function getOffers($pdo, $where = array()) { + $ids = self::getOfferIds($pdo, $where); + $offers = array(); + foreach ($ids as $id) { + $offers[$id] = new offer($pdo, $id); + } + return $offers; + } + + /** + * Get all assignment ids + * + * @see BusinessAdmin::getAssignments() This funtion returns instances of the assignment class instead of just the ids + * + * @param PDO $pdo The PDO class for database connection + * @param string[] $where An array of WHERE clauses that will be AND-ed + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public static function getAssignmentIds($pdo, $where = array()) { + $ids = array(); + $assignments = $pdo->query("SELECT `id` FROM `".constants::db_prefix."assignment`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); + foreach ($assignments as $assignment) { + $ids[] = $assignment['id']; + } + return $ids; + } + + /** + * Get all assignments + * + * @see BusinessAdmin::getAssignmentIds() This function returns just the ids of the assignments, and not instances of the assignment class + * + * @param PDO $pdo The PDO class for database connection + * @param string[] $where An array of WHERE clauses that will be AND-ed + * + * @throws PDOException If something went wrong with the database + * + * @return assignment[] An array indexed by id of instances of the assignment class + */ + public static function getAssignments($pdo, $where = array()) { + $ids = self::getAssignmentIds($pdo, $where); + $assignments = array(); + foreach ($ids as $id) { + $assignments[$id] = new assignment($pdo, $id); + } + return $assignments; + } + + /** + * Get all discount ids + * + * @see BusinessAdmin::getDiscounts() This funtion returns instances of the discount class instead of just the ids + * + * @param PDO $pdo The PDO class for database connection + * @param string[] $where An array of WHERE clauses that will be AND-ed + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public static function getDiscountIds($pdo, $where = array()) { + $ids = array(); + $discounts = $pdo->query("SELECT `id` FROM `".constants::db_prefix."discount`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); + foreach ($discounts as $discount) { + $ids[] = $discount['id']; + } + return $ids; + } + + /** + * Get all discounts + * + * @see BusinessAdmin::getDiscountIds() This function returns just the ids of the discounts, and not instances of the discount class + * + * @param PDO $pdo The PDO class for database connection + * @param string[] $where An array of WHERE clauses that will be AND-ed + * + * @throws PDOException If something went wrong with the database + * + * @return discount[] An array indexed by id of instances of the discount class + */ + public static function getDiscounts($pdo, $where = array()) { + $ids = self::getDiscountIds($pdo, $where); + $discounts = array(); + foreach ($ids as $id) { + $discounts[$id] = new discount($pdo, $id); + } + return $discounts; + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Create a new client + * + * @param PDO $pdo The database connection + * @param string $name The name for the new client + * + * @throws PDOException If something went wrong with the database + * + * @return client|bool A new instance of the client object, or false on failure + */ + public static function createClient($pdo, $name) { + $stmt = $pdo->prepare("INSERT INTO `".constants::db_prefix."client` (`name`) VALUES (?)"); + $stmt->execute(array($name)); + if ($stmt->rowCount() == 1) { + return new client($pdo, $pdo->lastInsertId()); + } else { + return false; + } + } + + /** + * Create a new file + * + * @param PDO $pdo The database connection + * @param string $filename The desired filename + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the file could not be created (due to permissions, file existed already, etc.), or the database record couldn't be added + * + * @return file A new instance of the file object + */ + public static function createFile($pdo, $filename) { + // Check for file existence + if (file_exists(constants::files_folder . $filename)) { + throw new Exception("$filename already exists."); + } + + // Try to create the file + if (file_put_contents(constants::files_folder . $filename, '') === false) { + throw new Exception("$filename could not be created. Check the permissions."); + } + + $stmt = $pdo->prepare("INSERT INTO `".constants::db_prefix."file` (`filename`) VALUES (?)"); + $stmt->execute(array($filename)); + if ($stmt->rowCount() == 1) { + return new file($pdo, $pdo->lastInsertId()); + } else { + unlink(constants::files_folder . $filename); + throw new Exception("$filename could not be added to the database"); + } + } + + /** + * Format a date nicely + * + * @todo implement $relatively = true + * + * @param int $timestamp The UNIX timestamp to format + * @param bool $with_time If false, only the date is returned; if false, also the time + * @param bool $full_date If true, a year will be outputted even if the date is in the current year + * @param bool $relatively Whether or not to show the date relatively (e.g. '1 day ago') (NOT IMPLEMENTED YET) + * + * @return string The formatted date + */ + public static function formatDate($timestamp, $with_time = true, $full_date = false, $relatively = false) { + $output = ''; + if (date('Y', $timestamp) == 1970) { + return 'never'; + } + if (date('d/m/Y') == date('d/m/Y', $timestamp)) { + return 'today'; + } + if (date('Y') != date('Y', $timestamp) || $full_date) { + $output .= date('Y-', $timestamp); + } + if (date('d/m/Y') != date('d/m/Y', $timestamp) || $full_date) { + $output .= date('m-d', $timestamp); + } + if ($with_time) { + $output .= date(' H:i', $timestamp); + } + + return $output; + } +} diff --git a/classes/FPDF.php b/classes/FPDF.php new file mode 100644 index 0000000..0dd1cb6 --- /dev/null +++ b/classes/FPDF.php @@ -0,0 +1,1804 @@ +_dochecks(); + // Initialization of properties + $this->page = 0; + $this->n = 2; + $this->buffer = ''; + $this->pages = array(); + $this->PageSizes = array(); + $this->state = 0; + $this->fonts = array(); + $this->FontFiles = array(); + $this->diffs = array(); + $this->images = array(); + $this->links = array(); + $this->InHeader = false; + $this->InFooter = false; + $this->lasth = 0; + $this->FontFamily = ''; + $this->FontStyle = ''; + $this->FontSizePt = 12; + $this->underline = false; + $this->DrawColor = '0 G'; + $this->FillColor = '0 g'; + $this->TextColor = '0 g'; + $this->ColorFlag = false; + $this->ws = 0; + // Font path + if(defined('FPDF_FONTPATH')) + { + $this->fontpath = FPDF_FONTPATH; + if(substr($this->fontpath,-1)!='/' && substr($this->fontpath,-1)!='\\') + $this->fontpath .= '/'; + } + elseif(is_dir(dirname(__FILE__).'/font')) + $this->fontpath = dirname(__FILE__).'/font/'; + else + $this->fontpath = ''; + // Core fonts + $this->CoreFonts = array('courier', 'helvetica', 'times', 'symbol', 'zapfdingbats'); + // Scale factor + if($unit=='pt') + $this->k = 1; + elseif($unit=='mm') + $this->k = 72/25.4; + elseif($unit=='cm') + $this->k = 72/2.54; + elseif($unit=='in') + $this->k = 72; + else + $this->Error('Incorrect unit: '.$unit); + // Page sizes + $this->StdPageSizes = array('a3'=>array(841.89,1190.55), 'a4'=>array(595.28,841.89), 'a5'=>array(420.94,595.28), + 'letter'=>array(612,792), 'legal'=>array(612,1008)); + $size = $this->_getpagesize($size); + $this->DefPageSize = $size; + $this->CurPageSize = $size; + // Page orientation + $orientation = strtolower($orientation); + if($orientation=='p' || $orientation=='portrait') + { + $this->DefOrientation = 'P'; + $this->w = $size[0]; + $this->h = $size[1]; + } + elseif($orientation=='l' || $orientation=='landscape') + { + $this->DefOrientation = 'L'; + $this->w = $size[1]; + $this->h = $size[0]; + } + else + $this->Error('Incorrect orientation: '.$orientation); + $this->CurOrientation = $this->DefOrientation; + $this->wPt = $this->w*$this->k; + $this->hPt = $this->h*$this->k; + // Page margins (1 cm) + $margin = 28.35/$this->k; + $this->SetMargins($margin,$margin); + // Interior cell margin (1 mm) + $this->cMargin = $margin/10; + // Line width (0.2 mm) + $this->LineWidth = .567/$this->k; + // Automatic page break + $this->SetAutoPageBreak(true,2*$margin); + // Default display mode + $this->SetDisplayMode('default'); + // Enable compression + $this->SetCompression(true); + // Set default PDF version number + $this->PDFVersion = '1.3'; +} + +function SetMargins($left, $top, $right=null) +{ + // Set left, top and right margins + $this->lMargin = $left; + $this->tMargin = $top; + if($right===null) + $right = $left; + $this->rMargin = $right; +} + +function SetLeftMargin($margin) +{ + // Set left margin + $this->lMargin = $margin; + if($this->page>0 && $this->x<$margin) + $this->x = $margin; +} + +function SetTopMargin($margin) +{ + // Set top margin + $this->tMargin = $margin; +} + +function SetRightMargin($margin) +{ + // Set right margin + $this->rMargin = $margin; +} + +function SetAutoPageBreak($auto, $margin=0) +{ + // Set auto page break mode and triggering margin + $this->AutoPageBreak = $auto; + $this->bMargin = $margin; + $this->PageBreakTrigger = $this->h-$margin; +} + +function SetDisplayMode($zoom, $layout='default') +{ + // Set display mode in viewer + if($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom)) + $this->ZoomMode = $zoom; + else + $this->Error('Incorrect zoom display mode: '.$zoom); + if($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default') + $this->LayoutMode = $layout; + else + $this->Error('Incorrect layout display mode: '.$layout); +} + +function SetCompression($compress) +{ + // Set page compression + if(function_exists('gzcompress')) + $this->compress = $compress; + else + $this->compress = false; +} + +function SetTitle($title, $isUTF8=false) +{ + // Title of document + if($isUTF8) + $title = $this->_UTF8toUTF16($title); + $this->title = $title; +} + +function SetSubject($subject, $isUTF8=false) +{ + // Subject of document + if($isUTF8) + $subject = $this->_UTF8toUTF16($subject); + $this->subject = $subject; +} + +function SetAuthor($author, $isUTF8=false) +{ + // Author of document + if($isUTF8) + $author = $this->_UTF8toUTF16($author); + $this->author = $author; +} + +function SetKeywords($keywords, $isUTF8=false) +{ + // Keywords of document + if($isUTF8) + $keywords = $this->_UTF8toUTF16($keywords); + $this->keywords = $keywords; +} + +function SetCreator($creator, $isUTF8=false) +{ + // Creator of document + if($isUTF8) + $creator = $this->_UTF8toUTF16($creator); + $this->creator = $creator; +} + +function AliasNbPages($alias='{nb}') +{ + // Define an alias for total number of pages + $this->AliasNbPages = $alias; +} + +function Error($msg) +{ + // Fatal error + die('FPDF error: '.$msg); +} + +function Open() +{ + // Begin document + $this->state = 1; +} + +function Close() +{ + // Terminate document + if($this->state==3) + return; + if($this->page==0) + $this->AddPage(); + // Page footer + $this->InFooter = true; + $this->Footer(); + $this->InFooter = false; + // Close page + $this->_endpage(); + // Close document + $this->_enddoc(); +} + +function AddPage($orientation='', $size='') +{ + // Start a new page + if($this->state==0) + $this->Open(); + $family = $this->FontFamily; + $style = $this->FontStyle.($this->underline ? 'U' : ''); + $fontsize = $this->FontSizePt; + $lw = $this->LineWidth; + $dc = $this->DrawColor; + $fc = $this->FillColor; + $tc = $this->TextColor; + $cf = $this->ColorFlag; + if($this->page>0) + { + // Page footer + $this->InFooter = true; + $this->Footer(); + $this->InFooter = false; + // Close page + $this->_endpage(); + } + // Start new page + $this->_beginpage($orientation,$size); + // Set line cap style to square + $this->_out('2 J'); + // Set line width + $this->LineWidth = $lw; + $this->_out(sprintf('%.2F w',$lw*$this->k)); + // Set font + if($family) + $this->SetFont($family,$style,$fontsize); + // Set colors + $this->DrawColor = $dc; + if($dc!='0 G') + $this->_out($dc); + $this->FillColor = $fc; + if($fc!='0 g') + $this->_out($fc); + $this->TextColor = $tc; + $this->ColorFlag = $cf; + // Page header + $this->InHeader = true; + $this->Header(); + $this->InHeader = false; + // Restore line width + if($this->LineWidth!=$lw) + { + $this->LineWidth = $lw; + $this->_out(sprintf('%.2F w',$lw*$this->k)); + } + // Restore font + if($family) + $this->SetFont($family,$style,$fontsize); + // Restore colors + if($this->DrawColor!=$dc) + { + $this->DrawColor = $dc; + $this->_out($dc); + } + if($this->FillColor!=$fc) + { + $this->FillColor = $fc; + $this->_out($fc); + } + $this->TextColor = $tc; + $this->ColorFlag = $cf; +} + +function Header() +{ + // To be implemented in your own inherited class +} + +function Footer() +{ + // To be implemented in your own inherited class +} + +function PageNo() +{ + // Get current page number + return $this->page; +} + +function SetDrawColor($r, $g=null, $b=null) +{ + // Set color for all stroking operations + if(($r==0 && $g==0 && $b==0) || $g===null) + $this->DrawColor = sprintf('%.3F G',$r/255); + else + $this->DrawColor = sprintf('%.3F %.3F %.3F RG',$r/255,$g/255,$b/255); + if($this->page>0) + $this->_out($this->DrawColor); +} + +function SetFillColor($r, $g=null, $b=null) +{ + // Set color for all filling operations + if(($r==0 && $g==0 && $b==0) || $g===null) + $this->FillColor = sprintf('%.3F g',$r/255); + else + $this->FillColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255); + $this->ColorFlag = ($this->FillColor!=$this->TextColor); + if($this->page>0) + $this->_out($this->FillColor); +} + +function SetTextColor($r, $g=null, $b=null) +{ + // Set color for text + if(($r==0 && $g==0 && $b==0) || $g===null) + $this->TextColor = sprintf('%.3F g',$r/255); + else + $this->TextColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255); + $this->ColorFlag = ($this->FillColor!=$this->TextColor); +} + +function GetStringWidth($s) +{ + // Get width of a string in the current font + $s = (string)$s; + $cw = &$this->CurrentFont['cw']; + $w = 0; + $l = strlen($s); + for($i=0;$i<$l;$i++) + $w += $cw[$s[$i]]; + return $w*$this->FontSize/1000; +} + +function SetLineWidth($width) +{ + // Set line width + $this->LineWidth = $width; + if($this->page>0) + $this->_out(sprintf('%.2F w',$width*$this->k)); +} + +function Line($x1, $y1, $x2, $y2) +{ + // Draw a line + $this->_out(sprintf('%.2F %.2F m %.2F %.2F l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k)); +} + +function Rect($x, $y, $w, $h, $style='') +{ + // Draw a rectangle + if($style=='F') + $op = 'f'; + elseif($style=='FD' || $style=='DF') + $op = 'B'; + else + $op = 'S'; + $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op)); +} + +function AddFont($family, $style='', $file='') +{ + // Add a TrueType, OpenType or Type1 font + $family = strtolower($family); + if($file=='') + $file = str_replace(' ','',$family).strtolower($style).'.php'; + $style = strtoupper($style); + if($style=='IB') + $style = 'BI'; + $fontkey = $family.$style; + if(isset($this->fonts[$fontkey])) + return; + $info = $this->_loadfont($file); + $info['i'] = count($this->fonts)+1; + if(!empty($info['diff'])) + { + // Search existing encodings + $n = array_search($info['diff'],$this->diffs); + if(!$n) + { + $n = count($this->diffs)+1; + $this->diffs[$n] = $info['diff']; + } + $info['diffn'] = $n; + } + if(!empty($info['file'])) + { + // Embedded font + if($info['type']=='TrueType') + $this->FontFiles[$info['file']] = array('length1'=>$info['originalsize']); + else + $this->FontFiles[$info['file']] = array('length1'=>$info['size1'], 'length2'=>$info['size2']); + } + $this->fonts[$fontkey] = $info; +} + +function SetFont($family, $style='', $size=0) +{ + // Select a font; size given in points + if($family=='') + $family = $this->FontFamily; + else + $family = strtolower($family); + $style = strtoupper($style); + if(strpos($style,'U')!==false) + { + $this->underline = true; + $style = str_replace('U','',$style); + } + else + $this->underline = false; + if($style=='IB') + $style = 'BI'; + if($size==0) + $size = $this->FontSizePt; + // Test if font is already selected + if($this->FontFamily==$family && $this->FontStyle==$style && $this->FontSizePt==$size) + return; + // Test if font is already loaded + $fontkey = $family.$style; + if(!isset($this->fonts[$fontkey])) + { + // Test if one of the core fonts + if($family=='arial') + $family = 'helvetica'; + if(in_array($family,$this->CoreFonts)) + { + if($family=='symbol' || $family=='zapfdingbats') + $style = ''; + $fontkey = $family.$style; + if(!isset($this->fonts[$fontkey])) + $this->AddFont($family,$style); + } + else + $this->Error('Undefined font: '.$family.' '.$style); + } + // Select it + $this->FontFamily = $family; + $this->FontStyle = $style; + $this->FontSizePt = $size; + $this->FontSize = $size/$this->k; + $this->CurrentFont = &$this->fonts[$fontkey]; + if($this->page>0) + $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); +} + +function SetFontSize($size) +{ + // Set font size in points + if($this->FontSizePt==$size) + return; + $this->FontSizePt = $size; + $this->FontSize = $size/$this->k; + if($this->page>0) + $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); +} + +function AddLink() +{ + // Create a new internal link + $n = count($this->links)+1; + $this->links[$n] = array(0, 0); + return $n; +} + +function SetLink($link, $y=0, $page=-1) +{ + // Set destination of internal link + if($y==-1) + $y = $this->y; + if($page==-1) + $page = $this->page; + $this->links[$link] = array($page, $y); +} + +function Link($x, $y, $w, $h, $link) +{ + // Put a link on the page + $this->PageLinks[$this->page][] = array($x*$this->k, $this->hPt-$y*$this->k, $w*$this->k, $h*$this->k, $link); +} + +function Text($x, $y, $txt) +{ + // Output a string + $s = sprintf('BT %.2F %.2F Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt)); + if($this->underline && $txt!='') + $s .= ' '.$this->_dounderline($x,$y,$txt); + if($this->ColorFlag) + $s = 'q '.$this->TextColor.' '.$s.' Q'; + $this->_out($s); +} + +function AcceptPageBreak() +{ + // Accept automatic page break or not + return $this->AutoPageBreak; +} + +function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='') +{ + // Output a cell + $k = $this->k; + if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) + { + // Automatic page break + $x = $this->x; + $ws = $this->ws; + if($ws>0) + { + $this->ws = 0; + $this->_out('0 Tw'); + } + $this->AddPage($this->CurOrientation,$this->CurPageSize); + $this->x = $x; + if($ws>0) + { + $this->ws = $ws; + $this->_out(sprintf('%.3F Tw',$ws*$k)); + } + } + if($w==0) + $w = $this->w-$this->rMargin-$this->x; + $s = ''; + if($fill || $border==1) + { + if($fill) + $op = ($border==1) ? 'B' : 'f'; + else + $op = 'S'; + $s = sprintf('%.2F %.2F %.2F %.2F re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op); + } + if(is_string($border)) + { + $x = $this->x; + $y = $this->y; + if(strpos($border,'L')!==false) + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k); + if(strpos($border,'T')!==false) + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k); + if(strpos($border,'R')!==false) + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + if(strpos($border,'B')!==false) + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + } + if($txt!=='') + { + if($align=='R') + $dx = $w-$this->cMargin-$this->GetStringWidth($txt); + elseif($align=='C') + $dx = ($w-$this->GetStringWidth($txt))/2; + else + $dx = $this->cMargin; + if($this->ColorFlag) + $s .= 'q '.$this->TextColor.' '; + $txt2 = str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt))); + $s .= sprintf('BT %.2F %.2F Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt2); + if($this->underline) + $s .= ' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt); + if($this->ColorFlag) + $s .= ' Q'; + if($link) + $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link); + } + if($s) + $this->_out($s); + $this->lasth = $h; + if($ln>0) + { + // Go to next line + $this->y += $h; + if($ln==1) + $this->x = $this->lMargin; + } + else + $this->x += $w; +} + +function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false) +{ + // Output text with automatic or explicit line breaks + $cw = &$this->CurrentFont['cw']; + if($w==0) + $w = $this->w-$this->rMargin-$this->x; + $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; + $s = str_replace("\r",'',$txt); + $nb = strlen($s); + if($nb>0 && $s[$nb-1]=="\n") + $nb--; + $b = 0; + if($border) + { + if($border==1) + { + $border = 'LTRB'; + $b = 'LRT'; + $b2 = 'LR'; + } + else + { + $b2 = ''; + if(strpos($border,'L')!==false) + $b2 .= 'L'; + if(strpos($border,'R')!==false) + $b2 .= 'R'; + $b = (strpos($border,'T')!==false) ? $b2.'T' : $b2; + } + } + $sep = -1; + $i = 0; + $j = 0; + $l = 0; + $ns = 0; + $nl = 1; + while($i<$nb) + { + // Get next character + $c = $s[$i]; + if($c=="\n") + { + // Explicit line break + if($this->ws>0) + { + $this->ws = 0; + $this->_out('0 Tw'); + } + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + $i++; + $sep = -1; + $j = $i; + $l = 0; + $ns = 0; + $nl++; + if($border && $nl==2) + $b = $b2; + continue; + } + if($c==' ') + { + $sep = $i; + $ls = $l; + $ns++; + } + $l += $cw[$c]; + if($l>$wmax) + { + // Automatic line break + if($sep==-1) + { + if($i==$j) + $i++; + if($this->ws>0) + { + $this->ws = 0; + $this->_out('0 Tw'); + } + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + } + else + { + if($align=='J') + { + $this->ws = ($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0; + $this->_out(sprintf('%.3F Tw',$this->ws*$this->k)); + } + $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill); + $i = $sep+1; + } + $sep = -1; + $j = $i; + $l = 0; + $ns = 0; + $nl++; + if($border && $nl==2) + $b = $b2; + } + else + $i++; + } + // Last chunk + if($this->ws>0) + { + $this->ws = 0; + $this->_out('0 Tw'); + } + if($border && strpos($border,'B')!==false) + $b .= 'B'; + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + $this->x = $this->lMargin; +} + +function Write($h, $txt, $link='') +{ + // Output text in flowing mode + $cw = &$this->CurrentFont['cw']; + $w = $this->w-$this->rMargin-$this->x; + $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; + $s = str_replace("\r",'',$txt); + $nb = strlen($s); + $sep = -1; + $i = 0; + $j = 0; + $l = 0; + $nl = 1; + while($i<$nb) + { + // Get next character + $c = $s[$i]; + if($c=="\n") + { + // Explicit line break + $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); + $i++; + $sep = -1; + $j = $i; + $l = 0; + if($nl==1) + { + $this->x = $this->lMargin; + $w = $this->w-$this->rMargin-$this->x; + $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; + } + $nl++; + continue; + } + if($c==' ') + $sep = $i; + $l += $cw[$c]; + if($l>$wmax) + { + // Automatic line break + if($sep==-1) + { + if($this->x>$this->lMargin) + { + // Move to next line + $this->x = $this->lMargin; + $this->y += $h; + $w = $this->w-$this->rMargin-$this->x; + $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; + $i++; + $nl++; + continue; + } + if($i==$j) + $i++; + $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); + } + else + { + $this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',0,$link); + $i = $sep+1; + } + $sep = -1; + $j = $i; + $l = 0; + if($nl==1) + { + $this->x = $this->lMargin; + $w = $this->w-$this->rMargin-$this->x; + $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; + } + $nl++; + } + else + $i++; + } + // Last chunk + if($i!=$j) + $this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',0,$link); +} + +function Ln($h=null) +{ + // Line feed; default value is last cell height + $this->x = $this->lMargin; + if($h===null) + $this->y += $this->lasth; + else + $this->y += $h; +} + +function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='') +{ + // Put an image on the page + if(!isset($this->images[$file])) + { + // First use of this image, get info + if($type=='') + { + $pos = strrpos($file,'.'); + if(!$pos) + $this->Error('Image file has no extension and no type was specified: '.$file); + $type = substr($file,$pos+1); + } + $type = strtolower($type); + if($type=='jpeg') + $type = 'jpg'; + $mtd = '_parse'.$type; + if(!method_exists($this,$mtd)) + $this->Error('Unsupported image type: '.$type); + $info = $this->$mtd($file); + $info['i'] = count($this->images)+1; + $this->images[$file] = $info; + } + else + $info = $this->images[$file]; + + // Automatic width and height calculation if needed + if($w==0 && $h==0) + { + // Put image at 96 dpi + $w = -96; + $h = -96; + } + if($w<0) + $w = -$info['w']*72/$w/$this->k; + if($h<0) + $h = -$info['h']*72/$h/$this->k; + if($w==0) + $w = $h*$info['w']/$info['h']; + if($h==0) + $h = $w*$info['h']/$info['w']; + + // Flowing mode + if($y===null) + { + if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) + { + // Automatic page break + $x2 = $this->x; + $this->AddPage($this->CurOrientation,$this->CurPageSize); + $this->x = $x2; + } + $y = $this->y; + $this->y += $h; + } + + if($x===null) + $x = $this->x; + $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i'])); + if($link) + $this->Link($x,$y,$w,$h,$link); +} + +function GetX() +{ + // Get x position + return $this->x; +} + +function SetX($x) +{ + // Set x position + if($x>=0) + $this->x = $x; + else + $this->x = $this->w+$x; +} + +function GetY() +{ + // Get y position + return $this->y; +} + +function SetY($y) +{ + // Set y position and reset x + $this->x = $this->lMargin; + if($y>=0) + $this->y = $y; + else + $this->y = $this->h+$y; +} + +function SetXY($x, $y) +{ + // Set x and y positions + $this->SetY($y); + $this->SetX($x); +} + +function Output($name='', $dest='') +{ + // Output PDF to some destination + if($this->state<3) + $this->Close(); + $dest = strtoupper($dest); + if($dest=='') + { + if($name=='') + { + $name = 'doc.pdf'; + $dest = 'I'; + } + else + $dest = 'F'; + } + switch($dest) + { + case 'I': + // Send to standard output + $this->_checkoutput(); + if(PHP_SAPI!='cli') + { + // We send to a browser + header('Content-Type: application/pdf'); + header('Content-Disposition: inline; filename="'.$name.'"'); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Pragma: public'); + } + echo $this->buffer; + break; + case 'D': + // Download file + $this->_checkoutput(); + header('Content-Type: application/x-download'); + header('Content-Disposition: attachment; filename="'.$name.'"'); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Pragma: public'); + echo $this->buffer; + break; + case 'F': + // Save to local file + $f = fopen($name,'wb'); + if(!$f) + $this->Error('Unable to create output file: '.$name); + fwrite($f,$this->buffer,strlen($this->buffer)); + fclose($f); + break; + case 'S': + // Return as a string + return $this->buffer; + default: + $this->Error('Incorrect output destination: '.$dest); + } + return ''; +} + +/******************************************************************************* +* * +* Protected methods * +* * +*******************************************************************************/ +function _dochecks() +{ + // Check availability of %F + if(sprintf('%.1F',1.0)!='1.0') + $this->Error('This version of PHP is not supported'); + // Check mbstring overloading + if(ini_get('mbstring.func_overload') & 2) + $this->Error('mbstring overloading must be disabled'); + // Ensure runtime magic quotes are disabled + if(get_magic_quotes_runtime()) + @set_magic_quotes_runtime(0); +} + +function _checkoutput() +{ + if(PHP_SAPI!='cli') + { + if(headers_sent($file,$line)) + $this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)"); + } + if(ob_get_length()) + { + // The output buffer is not empty + if(preg_match('/^(\xEF\xBB\xBF)?\s*$/',ob_get_contents())) + { + // It contains only a UTF-8 BOM and/or whitespace, let's clean it + ob_clean(); + } + else + $this->Error("Some data has already been output, can't send PDF file"); + } +} + +function _getpagesize($size) +{ + if(is_string($size)) + { + $size = strtolower($size); + if(!isset($this->StdPageSizes[$size])) + $this->Error('Unknown page size: '.$size); + $a = $this->StdPageSizes[$size]; + return array($a[0]/$this->k, $a[1]/$this->k); + } + else + { + if($size[0]>$size[1]) + return array($size[1], $size[0]); + else + return $size; + } +} + +function _beginpage($orientation, $size) +{ + $this->page++; + $this->pages[$this->page] = ''; + $this->state = 2; + $this->x = $this->lMargin; + $this->y = $this->tMargin; + $this->FontFamily = ''; + // Check page size and orientation + if($orientation=='') + $orientation = $this->DefOrientation; + else + $orientation = strtoupper($orientation[0]); + if($size=='') + $size = $this->DefPageSize; + else + $size = $this->_getpagesize($size); + if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1]) + { + // New size or orientation + if($orientation=='P') + { + $this->w = $size[0]; + $this->h = $size[1]; + } + else + { + $this->w = $size[1]; + $this->h = $size[0]; + } + $this->wPt = $this->w*$this->k; + $this->hPt = $this->h*$this->k; + $this->PageBreakTrigger = $this->h-$this->bMargin; + $this->CurOrientation = $orientation; + $this->CurPageSize = $size; + } + if($orientation!=$this->DefOrientation || $size[0]!=$this->DefPageSize[0] || $size[1]!=$this->DefPageSize[1]) + $this->PageSizes[$this->page] = array($this->wPt, $this->hPt); +} + +function _endpage() +{ + $this->state = 1; +} + +function _loadfont($font) +{ + // Load a font definition file from the font directory + include($this->fontpath.$font); + $a = get_defined_vars(); + if(!isset($a['name'])) + $this->Error('Could not include font definition file'); + return $a; +} + +function _escape($s) +{ + // Escape special characters in strings + $s = str_replace('\\','\\\\',$s); + $s = str_replace('(','\\(',$s); + $s = str_replace(')','\\)',$s); + $s = str_replace("\r",'\\r',$s); + return $s; +} + +function _textstring($s) +{ + // Format a text string + return '('.$this->_escape($s).')'; +} + +function _UTF8toUTF16($s) +{ + // Convert UTF-8 to UTF-16BE with BOM + $res = "\xFE\xFF"; + $nb = strlen($s); + $i = 0; + while($i<$nb) + { + $c1 = ord($s[$i++]); + if($c1>=224) + { + // 3-byte character + $c2 = ord($s[$i++]); + $c3 = ord($s[$i++]); + $res .= chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2)); + $res .= chr((($c2 & 0x03)<<6) + ($c3 & 0x3F)); + } + elseif($c1>=192) + { + // 2-byte character + $c2 = ord($s[$i++]); + $res .= chr(($c1 & 0x1C)>>2); + $res .= chr((($c1 & 0x03)<<6) + ($c2 & 0x3F)); + } + else + { + // Single-byte character + $res .= "\0".chr($c1); + } + } + return $res; +} + +function _dounderline($x, $y, $txt) +{ + // Underline text + $up = $this->CurrentFont['up']; + $ut = $this->CurrentFont['ut']; + $w = $this->GetStringWidth($txt)+$this->ws*substr_count($txt,' '); + return sprintf('%.2F %.2F %.2F %.2F re f',$x*$this->k,($this->h-($y-$up/1000*$this->FontSize))*$this->k,$w*$this->k,-$ut/1000*$this->FontSizePt); +} + +function _parsejpg($file) +{ + // Extract info from a JPEG file + $a = getimagesize($file); + if(!$a) + $this->Error('Missing or incorrect image file: '.$file); + if($a[2]!=2) + $this->Error('Not a JPEG file: '.$file); + if(!isset($a['channels']) || $a['channels']==3) + $colspace = 'DeviceRGB'; + elseif($a['channels']==4) + $colspace = 'DeviceCMYK'; + else + $colspace = 'DeviceGray'; + $bpc = isset($a['bits']) ? $a['bits'] : 8; + $data = file_get_contents($file); + return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data); +} + +function _parsepng($file) +{ + // Extract info from a PNG file + $f = fopen($file,'rb'); + if(!$f) + $this->Error('Can\'t open image file: '.$file); + $info = $this->_parsepngstream($f,$file); + fclose($f); + return $info; +} + +function _parsepngstream($f, $file) +{ + // Check signature + if($this->_readstream($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) + $this->Error('Not a PNG file: '.$file); + + // Read header chunk + $this->_readstream($f,4); + if($this->_readstream($f,4)!='IHDR') + $this->Error('Incorrect PNG file: '.$file); + $w = $this->_readint($f); + $h = $this->_readint($f); + $bpc = ord($this->_readstream($f,1)); + if($bpc>8) + $this->Error('16-bit depth not supported: '.$file); + $ct = ord($this->_readstream($f,1)); + if($ct==0 || $ct==4) + $colspace = 'DeviceGray'; + elseif($ct==2 || $ct==6) + $colspace = 'DeviceRGB'; + elseif($ct==3) + $colspace = 'Indexed'; + else + $this->Error('Unknown color type: '.$file); + if(ord($this->_readstream($f,1))!=0) + $this->Error('Unknown compression method: '.$file); + if(ord($this->_readstream($f,1))!=0) + $this->Error('Unknown filter method: '.$file); + if(ord($this->_readstream($f,1))!=0) + $this->Error('Interlacing not supported: '.$file); + $this->_readstream($f,4); + $dp = '/Predictor 15 /Colors '.($colspace=='DeviceRGB' ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w; + + // Scan chunks looking for palette, transparency and image data + $pal = ''; + $trns = ''; + $data = ''; + do + { + $n = $this->_readint($f); + $type = $this->_readstream($f,4); + if($type=='PLTE') + { + // Read palette + $pal = $this->_readstream($f,$n); + $this->_readstream($f,4); + } + elseif($type=='tRNS') + { + // Read transparency info + $t = $this->_readstream($f,$n); + if($ct==0) + $trns = array(ord(substr($t,1,1))); + elseif($ct==2) + $trns = array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1))); + else + { + $pos = strpos($t,chr(0)); + if($pos!==false) + $trns = array($pos); + } + $this->_readstream($f,4); + } + elseif($type=='IDAT') + { + // Read image data block + $data .= $this->_readstream($f,$n); + $this->_readstream($f,4); + } + elseif($type=='IEND') + break; + else + $this->_readstream($f,$n+4); + } + while($n); + + if($colspace=='Indexed' && empty($pal)) + $this->Error('Missing palette in '.$file); + $info = array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'dp'=>$dp, 'pal'=>$pal, 'trns'=>$trns); + if($ct>=4) + { + // Extract alpha channel + if(!function_exists('gzuncompress')) + $this->Error('Zlib not available, can\'t handle alpha channel: '.$file); + $data = gzuncompress($data); + $color = ''; + $alpha = ''; + if($ct==4) + { + // Gray image + $len = 2*$w; + for($i=0;$i<$h;$i++) + { + $pos = (1+$len)*$i; + $color .= $data[$pos]; + $alpha .= $data[$pos]; + $line = substr($data,$pos+1,$len); + $color .= preg_replace('/(.)./s','$1',$line); + $alpha .= preg_replace('/.(.)/s','$1',$line); + } + } + else + { + // RGB image + $len = 4*$w; + for($i=0;$i<$h;$i++) + { + $pos = (1+$len)*$i; + $color .= $data[$pos]; + $alpha .= $data[$pos]; + $line = substr($data,$pos+1,$len); + $color .= preg_replace('/(.{3})./s','$1',$line); + $alpha .= preg_replace('/.{3}(.)/s','$1',$line); + } + } + unset($data); + $data = gzcompress($color); + $info['smask'] = gzcompress($alpha); + if($this->PDFVersion<'1.4') + $this->PDFVersion = '1.4'; + } + $info['data'] = $data; + return $info; +} + +function _readstream($f, $n) +{ + // Read n bytes from stream + $res = ''; + while($n>0 && !feof($f)) + { + $s = fread($f,$n); + if($s===false) + $this->Error('Error while reading stream'); + $n -= strlen($s); + $res .= $s; + } + if($n>0) + $this->Error('Unexpected end of stream'); + return $res; +} + +function _readint($f) +{ + // Read a 4-byte integer from stream + $a = unpack('Ni',$this->_readstream($f,4)); + return $a['i']; +} + +function _parsegif($file) +{ + // Extract info from a GIF file (via PNG conversion) + if(!function_exists('imagepng')) + $this->Error('GD extension is required for GIF support'); + if(!function_exists('imagecreatefromgif')) + $this->Error('GD has no GIF read support'); + $im = imagecreatefromgif($file); + if(!$im) + $this->Error('Missing or incorrect image file: '.$file); + imageinterlace($im,0); + $f = @fopen('php://temp','rb+'); + if($f) + { + // Perform conversion in memory + ob_start(); + imagepng($im); + $data = ob_get_clean(); + imagedestroy($im); + fwrite($f,$data); + rewind($f); + $info = $this->_parsepngstream($f,$file); + fclose($f); + } + else + { + // Use temporary file + $tmp = tempnam('.','gif'); + if(!$tmp) + $this->Error('Unable to create a temporary file'); + if(!imagepng($im,$tmp)) + $this->Error('Error while saving to temporary file'); + imagedestroy($im); + $info = $this->_parsepng($tmp); + unlink($tmp); + } + return $info; +} + +function _newobj() +{ + // Begin a new object + $this->n++; + $this->offsets[$this->n] = strlen($this->buffer); + $this->_out($this->n.' 0 obj'); +} + +function _putstream($s) +{ + $this->_out('stream'); + $this->_out($s); + $this->_out('endstream'); +} + +function _out($s) +{ + // Add a line to the document + if($this->state==2) + $this->pages[$this->page] .= $s."\n"; + else + $this->buffer .= $s."\n"; +} + +function _putpages() +{ + $nb = $this->page; + if(!empty($this->AliasNbPages)) + { + // Replace number of pages + for($n=1;$n<=$nb;$n++) + $this->pages[$n] = str_replace($this->AliasNbPages,$nb,$this->pages[$n]); + } + if($this->DefOrientation=='P') + { + $wPt = $this->DefPageSize[0]*$this->k; + $hPt = $this->DefPageSize[1]*$this->k; + } + else + { + $wPt = $this->DefPageSize[1]*$this->k; + $hPt = $this->DefPageSize[0]*$this->k; + } + $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; + for($n=1;$n<=$nb;$n++) + { + // Page + $this->_newobj(); + $this->_out('<_out('/Parent 1 0 R'); + if(isset($this->PageSizes[$n])) + $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]',$this->PageSizes[$n][0],$this->PageSizes[$n][1])); + $this->_out('/Resources 2 0 R'); + if(isset($this->PageLinks[$n])) + { + // Links + $annots = '/Annots ['; + foreach($this->PageLinks[$n] as $pl) + { + $rect = sprintf('%.2F %.2F %.2F %.2F',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]); + $annots .= '<_textstring($pl[4]).'>>>>'; + else + { + $l = $this->links[$pl[4]]; + $h = isset($this->PageSizes[$l[0]]) ? $this->PageSizes[$l[0]][1] : $hPt; + $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>',1+2*$l[0],$h-$l[1]*$this->k); + } + } + $this->_out($annots.']'); + } + if($this->PDFVersion>'1.3') + $this->_out('/Group <>'); + $this->_out('/Contents '.($this->n+1).' 0 R>>'); + $this->_out('endobj'); + // Page content + $p = ($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n]; + $this->_newobj(); + $this->_out('<<'.$filter.'/Length '.strlen($p).'>>'); + $this->_putstream($p); + $this->_out('endobj'); + } + // Pages root + $this->offsets[1] = strlen($this->buffer); + $this->_out('1 0 obj'); + $this->_out('<_out($kids.']'); + $this->_out('/Count '.$nb); + $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]',$wPt,$hPt)); + $this->_out('>>'); + $this->_out('endobj'); +} + +function _putfonts() +{ + $nf = $this->n; + foreach($this->diffs as $diff) + { + // Encodings + $this->_newobj(); + $this->_out('<>'); + $this->_out('endobj'); + } + foreach($this->FontFiles as $file=>$info) + { + // Font file embedding + $this->_newobj(); + $this->FontFiles[$file]['n'] = $this->n; + $font = file_get_contents($this->fontpath.$file,true); + if(!$font) + $this->Error('Font file not found: '.$file); + $compressed = (substr($file,-2)=='.z'); + if(!$compressed && isset($info['length2'])) + $font = substr($font,6,$info['length1']).substr($font,6+$info['length1']+6,$info['length2']); + $this->_out('<_out('/Filter /FlateDecode'); + $this->_out('/Length1 '.$info['length1']); + if(isset($info['length2'])) + $this->_out('/Length2 '.$info['length2'].' /Length3 0'); + $this->_out('>>'); + $this->_putstream($font); + $this->_out('endobj'); + } + foreach($this->fonts as $k=>$font) + { + // Font objects + $this->fonts[$k]['n'] = $this->n+1; + $type = $font['type']; + $name = $font['name']; + if($type=='Core') + { + // Core font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /Type1'); + if($name!='Symbol' && $name!='ZapfDingbats') + $this->_out('/Encoding /WinAnsiEncoding'); + $this->_out('>>'); + $this->_out('endobj'); + } + elseif($type=='Type1' || $type=='TrueType') + { + // Additional Type1 or TrueType/OpenType font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /'.$type); + $this->_out('/FirstChar 32 /LastChar 255'); + $this->_out('/Widths '.($this->n+1).' 0 R'); + $this->_out('/FontDescriptor '.($this->n+2).' 0 R'); + if(isset($font['diffn'])) + $this->_out('/Encoding '.($nf+$font['diffn']).' 0 R'); + else + $this->_out('/Encoding /WinAnsiEncoding'); + $this->_out('>>'); + $this->_out('endobj'); + // Widths + $this->_newobj(); + $cw = &$font['cw']; + $s = '['; + for($i=32;$i<=255;$i++) + $s .= $cw[chr($i)].' '; + $this->_out($s.']'); + $this->_out('endobj'); + // Descriptor + $this->_newobj(); + $s = '<$v) + $s .= ' /'.$k.' '.$v; + if(!empty($font['file'])) + $s .= ' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R'; + $this->_out($s.'>>'); + $this->_out('endobj'); + } + else + { + // Allow for additional types + $mtd = '_put'.strtolower($type); + if(!method_exists($this,$mtd)) + $this->Error('Unsupported font type: '.$type); + $this->$mtd($font); + } + } +} + +function _putimages() +{ + foreach(array_keys($this->images) as $file) + { + $this->_putimage($this->images[$file]); + unset($this->images[$file]['data']); + unset($this->images[$file]['smask']); + } +} + +function _putimage(&$info) +{ + $this->_newobj(); + $info['n'] = $this->n; + $this->_out('<_out('/Subtype /Image'); + $this->_out('/Width '.$info['w']); + $this->_out('/Height '.$info['h']); + if($info['cs']=='Indexed') + $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]'); + else + { + $this->_out('/ColorSpace /'.$info['cs']); + if($info['cs']=='DeviceCMYK') + $this->_out('/Decode [1 0 1 0 1 0 1 0]'); + } + $this->_out('/BitsPerComponent '.$info['bpc']); + if(isset($info['f'])) + $this->_out('/Filter /'.$info['f']); + if(isset($info['dp'])) + $this->_out('/DecodeParms <<'.$info['dp'].'>>'); + if(isset($info['trns']) && is_array($info['trns'])) + { + $trns = ''; + for($i=0;$i_out('/Mask ['.$trns.']'); + } + if(isset($info['smask'])) + $this->_out('/SMask '.($this->n+1).' 0 R'); + $this->_out('/Length '.strlen($info['data']).'>>'); + $this->_putstream($info['data']); + $this->_out('endobj'); + // Soft mask + if(isset($info['smask'])) + { + $dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns '.$info['w']; + $smask = array('w'=>$info['w'], 'h'=>$info['h'], 'cs'=>'DeviceGray', 'bpc'=>8, 'f'=>$info['f'], 'dp'=>$dp, 'data'=>$info['smask']); + $this->_putimage($smask); + } + // Palette + if($info['cs']=='Indexed') + { + $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; + $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal']; + $this->_newobj(); + $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>'); + $this->_putstream($pal); + $this->_out('endobj'); + } +} + +function _putxobjectdict() +{ + foreach($this->images as $image) + $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); +} + +function _putresourcedict() +{ + $this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); + $this->_out('/Font <<'); + foreach($this->fonts as $font) + $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R'); + $this->_out('>>'); + $this->_out('/XObject <<'); + $this->_putxobjectdict(); + $this->_out('>>'); +} + +function _putresources() +{ + $this->_putfonts(); + $this->_putimages(); + // Resource dictionary + $this->offsets[2] = strlen($this->buffer); + $this->_out('2 0 obj'); + $this->_out('<<'); + $this->_putresourcedict(); + $this->_out('>>'); + $this->_out('endobj'); +} + +function _putinfo() +{ + $this->_out('/Producer '.$this->_textstring('FPDF '.FPDF_VERSION)); + if(!empty($this->title)) + $this->_out('/Title '.$this->_textstring($this->title)); + if(!empty($this->subject)) + $this->_out('/Subject '.$this->_textstring($this->subject)); + if(!empty($this->author)) + $this->_out('/Author '.$this->_textstring($this->author)); + if(!empty($this->keywords)) + $this->_out('/Keywords '.$this->_textstring($this->keywords)); + if(!empty($this->creator)) + $this->_out('/Creator '.$this->_textstring($this->creator)); + $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis'))); +} + +function _putcatalog() +{ + $this->_out('/Type /Catalog'); + $this->_out('/Pages 1 0 R'); + if($this->ZoomMode=='fullpage') + $this->_out('/OpenAction [3 0 R /Fit]'); + elseif($this->ZoomMode=='fullwidth') + $this->_out('/OpenAction [3 0 R /FitH null]'); + elseif($this->ZoomMode=='real') + $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); + elseif(!is_string($this->ZoomMode)) + $this->_out('/OpenAction [3 0 R /XYZ null null '.sprintf('%.2F',$this->ZoomMode/100).']'); + if($this->LayoutMode=='single') + $this->_out('/PageLayout /SinglePage'); + elseif($this->LayoutMode=='continuous') + $this->_out('/PageLayout /OneColumn'); + elseif($this->LayoutMode=='two') + $this->_out('/PageLayout /TwoColumnLeft'); +} + +function _putheader() +{ + $this->_out('%PDF-'.$this->PDFVersion); +} + +function _puttrailer() +{ + $this->_out('/Size '.($this->n+1)); + $this->_out('/Root '.$this->n.' 0 R'); + $this->_out('/Info '.($this->n-1).' 0 R'); +} + +function _enddoc() +{ + $this->_putheader(); + $this->_putpages(); + $this->_putresources(); + // Info + $this->_newobj(); + $this->_out('<<'); + $this->_putinfo(); + $this->_out('>>'); + $this->_out('endobj'); + // Catalog + $this->_newobj(); + $this->_out('<<'); + $this->_putcatalog(); + $this->_out('>>'); + $this->_out('endobj'); + // Cross-ref + $o = strlen($this->buffer); + $this->_out('xref'); + $this->_out('0 '.($this->n+1)); + $this->_out('0000000000 65535 f '); + for($i=1;$i<=$this->n;$i++) + $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i])); + // Trailer + $this->_out('trailer'); + $this->_out('<<'); + $this->_puttrailer(); + $this->_out('>>'); + $this->_out('startxref'); + $this->_out($o); + $this->_out('%%EOF'); + $this->state = 3; +} +// End of class +} + +// Handle special IE contype request +if(isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT']=='contype') +{ + header('Content-Type: application/pdf'); + exit; +} + +?> diff --git a/classes/Parsedown.class.php b/classes/Parsedown.class.php deleted file mode 120000 index fda2d8f..0000000 --- a/classes/Parsedown.class.php +++ /dev/null @@ -1 +0,0 @@ -../modules/parsedown/Parsedown.php \ No newline at end of file diff --git a/classes/Parsedown.php b/classes/Parsedown.php new file mode 120000 index 0000000..fda2d8f --- /dev/null +++ b/classes/Parsedown.php @@ -0,0 +1 @@ +../modules/parsedown/Parsedown.php \ No newline at end of file diff --git a/classes/assignment.class.php b/classes/assignment.class.php deleted file mode 100644 index 9b7de09..0000000 --- a/classes/assignment.class.php +++ /dev/null @@ -1,316 +0,0 @@ -. - */ - -/** - * An interface to the assignment table in the database - */ -class assignment { - /** - * @var pdo $pdo The PDO class for database communication - * @var int $id The id of the assignment - * @var int $offerId The id of the offer this assignment is linked to - * @var string $title The title of the assignment - * @var string $description The description of the assignment - * @var int $hours The amount of hours of the assignment - * @var float $price_per_hour The price per hour for this assignment, in your valuta - * @var float $vat The percentage of VAT to calculate on this assignment - */ - protected $pdo, $offerId, $id, $title, $description, $hours, $price_per_hour, $vat; - - const SUBTOTAL = 1; - const VAT = 2; - const TOTAL = 3; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the assignment to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the assignment could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."assignment` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The assignment with id '$id' could not be found."); - } - $assignment = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $assignment['id']; - $this->offerId = $assignment['offerId']; - $this->title = $assignment['title']; - $this->description = $assignment['description']; - $this->hours = $assignment['hours']; - $this->price_per_hour = $assignment['price_per_hour']; - $this->vat = $assignment['VAT_percentage']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the assignment - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the ID of the offer that this assignment is linked to - * - * @return int The ID - */ - public function getOfferId() { - return $this->offerId; - } - - /** - * Get the offer that this assignment is linked to - * - * @return offer The offer - */ - public function getOffer() { - return new offer($this->pdo, $this->offerId); - } - - /** - * Get the title of the assignment - * - * @return string The title - */ - public function getTitle() { - return $this->title; - } - - /** - * Set the title of the assignment - * - * @param string $title The new title for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setTitle($title) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `title`=? WHERE `id`=?"); - $stmt->execute(array($title, $this->id)); - if ($stmt->rowCount() == 1) { - $this->title = $title; - return true; - } else { - return false; - } - } - - /** - * Get the description of the assignment - * - * @param bool $parseMarkdown Whether or not to parse markdown - * - * @return string The description - */ - public function getDescription($parseMarkdown = true) { - if ($parseMarkdown) { - $pd = new Parsedown; - return $pd->text($this->description); - } else { - return $this->description; - } - } - - /** - * Set the description of the assignment - * - * @param string $description The new description for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setDescription($description) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `description`=? WHERE `id`=?"); - $stmt->execute(array($description, $this->id)); - if ($stmt->rowCount() == 1) { - $this->description = $description; - return true; - } else { - return false; - } - } - - /** - * Get the amount of hours of the assignment - * - * @return int The amount of hours - */ - public function getHours() { - return $this->hours; - } - - /** - * Set the amount of hours of the assignment - * - * @param int $hours The new amount hours for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setHours($hours) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `hours`=? WHERE `id`=?"); - $stmt->execute(array($hours, $this->id)); - if ($stmt->rowCount() == 1) { - $this->hours = $hours; - return true; - } else { - return false; - } - } - - /** - * Get the price per hour of the assignment - * - * @return float The price per hour - */ - public function getPricePerHour() { - return $this->price_per_hour; - } - - /** - * Set the price per hour of the assignment - * - * @param float $price_per_hour The new price per hour for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setPricePerHour($price_per_hour) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `price_per_hour`=? WHERE `id`=?"); - $stmt->execute(array($price_per_hour, $this->id)); - if ($stmt->rowCount() == 1) { - $this->price_per_hour = $price_per_hour; - return true; - } else { - return false; - } - } - - /** - * Get the VAT percentage of the assignment - * - * @return float The VAT percentage - */ - public function getVAT() { - return $this->vat; - } - - /** - * Set the VAT percentage of the assignment - * - * @param float $vat The new VAT percentage for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setVAT($vat) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `VAT_percentage`=? WHERE `id`=?"); - $stmt->execute(array($vat, $this->id)); - if ($stmt->rowCount() == 1) { - $this->vat = $vat; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Calculate useful numbers about the assignment - * - * Subtotal: price_per_hour \* hours - * - * VAT: subtotal \* VAT_percentage - * - * Total: subtotal + VAT - * - * @param int $what Any of assignment::SUBTOTAL, assignment::VAT, assignment::TOTAL - * @param int $round How many decimals to round on - * @param bool $format Whether to format the number nicely (for output) or not (for calculations) - * - * @throws PDOException If something went wrong with the database - * - * @return float|bool The calculated value rounded on $round decimals, or false when the input is incorrect - */ - public function calculate($what = self::TOTAL, $round = 2, $format = true) { - $return = 0; - switch ($what) { - case self::SUBTOTAL: - $return = $this->getPricePerHour() * $this->getHours(); - break; - case self::VAT: - $return = $this->calculate(self::SUBTOTAL, $round + 1, false) * $this->getVAT() / 100; - break; - case self::TOTAL: - $return = $this->calculate(self::SUBTOTAL, $round + 1, false) + $this->calculate(self::VAT, $round + 1, false); - break; - default: - return false; - } - if ($format) { - return number_format($return, $round); - } else { - return round($return, $round); - } - } - - /** - * Remove this assignment from the database - * - * If this doesn't succeed (i.e. false is returned), that means the assignment was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."assignment` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } -} \ No newline at end of file diff --git a/classes/assignment.php b/classes/assignment.php new file mode 100644 index 0000000..9b7de09 --- /dev/null +++ b/classes/assignment.php @@ -0,0 +1,316 @@ +. + */ + +/** + * An interface to the assignment table in the database + */ +class assignment { + /** + * @var pdo $pdo The PDO class for database communication + * @var int $id The id of the assignment + * @var int $offerId The id of the offer this assignment is linked to + * @var string $title The title of the assignment + * @var string $description The description of the assignment + * @var int $hours The amount of hours of the assignment + * @var float $price_per_hour The price per hour for this assignment, in your valuta + * @var float $vat The percentage of VAT to calculate on this assignment + */ + protected $pdo, $offerId, $id, $title, $description, $hours, $price_per_hour, $vat; + + const SUBTOTAL = 1; + const VAT = 2; + const TOTAL = 3; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the assignment to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the assignment could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."assignment` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The assignment with id '$id' could not be found."); + } + $assignment = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $assignment['id']; + $this->offerId = $assignment['offerId']; + $this->title = $assignment['title']; + $this->description = $assignment['description']; + $this->hours = $assignment['hours']; + $this->price_per_hour = $assignment['price_per_hour']; + $this->vat = $assignment['VAT_percentage']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the assignment + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the ID of the offer that this assignment is linked to + * + * @return int The ID + */ + public function getOfferId() { + return $this->offerId; + } + + /** + * Get the offer that this assignment is linked to + * + * @return offer The offer + */ + public function getOffer() { + return new offer($this->pdo, $this->offerId); + } + + /** + * Get the title of the assignment + * + * @return string The title + */ + public function getTitle() { + return $this->title; + } + + /** + * Set the title of the assignment + * + * @param string $title The new title for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setTitle($title) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `title`=? WHERE `id`=?"); + $stmt->execute(array($title, $this->id)); + if ($stmt->rowCount() == 1) { + $this->title = $title; + return true; + } else { + return false; + } + } + + /** + * Get the description of the assignment + * + * @param bool $parseMarkdown Whether or not to parse markdown + * + * @return string The description + */ + public function getDescription($parseMarkdown = true) { + if ($parseMarkdown) { + $pd = new Parsedown; + return $pd->text($this->description); + } else { + return $this->description; + } + } + + /** + * Set the description of the assignment + * + * @param string $description The new description for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setDescription($description) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `description`=? WHERE `id`=?"); + $stmt->execute(array($description, $this->id)); + if ($stmt->rowCount() == 1) { + $this->description = $description; + return true; + } else { + return false; + } + } + + /** + * Get the amount of hours of the assignment + * + * @return int The amount of hours + */ + public function getHours() { + return $this->hours; + } + + /** + * Set the amount of hours of the assignment + * + * @param int $hours The new amount hours for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setHours($hours) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `hours`=? WHERE `id`=?"); + $stmt->execute(array($hours, $this->id)); + if ($stmt->rowCount() == 1) { + $this->hours = $hours; + return true; + } else { + return false; + } + } + + /** + * Get the price per hour of the assignment + * + * @return float The price per hour + */ + public function getPricePerHour() { + return $this->price_per_hour; + } + + /** + * Set the price per hour of the assignment + * + * @param float $price_per_hour The new price per hour for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setPricePerHour($price_per_hour) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `price_per_hour`=? WHERE `id`=?"); + $stmt->execute(array($price_per_hour, $this->id)); + if ($stmt->rowCount() == 1) { + $this->price_per_hour = $price_per_hour; + return true; + } else { + return false; + } + } + + /** + * Get the VAT percentage of the assignment + * + * @return float The VAT percentage + */ + public function getVAT() { + return $this->vat; + } + + /** + * Set the VAT percentage of the assignment + * + * @param float $vat The new VAT percentage for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setVAT($vat) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `VAT_percentage`=? WHERE `id`=?"); + $stmt->execute(array($vat, $this->id)); + if ($stmt->rowCount() == 1) { + $this->vat = $vat; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Calculate useful numbers about the assignment + * + * Subtotal: price_per_hour \* hours + * + * VAT: subtotal \* VAT_percentage + * + * Total: subtotal + VAT + * + * @param int $what Any of assignment::SUBTOTAL, assignment::VAT, assignment::TOTAL + * @param int $round How many decimals to round on + * @param bool $format Whether to format the number nicely (for output) or not (for calculations) + * + * @throws PDOException If something went wrong with the database + * + * @return float|bool The calculated value rounded on $round decimals, or false when the input is incorrect + */ + public function calculate($what = self::TOTAL, $round = 2, $format = true) { + $return = 0; + switch ($what) { + case self::SUBTOTAL: + $return = $this->getPricePerHour() * $this->getHours(); + break; + case self::VAT: + $return = $this->calculate(self::SUBTOTAL, $round + 1, false) * $this->getVAT() / 100; + break; + case self::TOTAL: + $return = $this->calculate(self::SUBTOTAL, $round + 1, false) + $this->calculate(self::VAT, $round + 1, false); + break; + default: + return false; + } + if ($format) { + return number_format($return, $round); + } else { + return round($return, $round); + } + } + + /** + * Remove this assignment from the database + * + * If this doesn't succeed (i.e. false is returned), that means the assignment was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."assignment` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } +} \ No newline at end of file diff --git a/classes/client.class.php b/classes/client.class.php deleted file mode 100644 index 1b45bae..0000000 --- a/classes/client.class.php +++ /dev/null @@ -1,195 +0,0 @@ -. - */ - -/** - * An interface to the client table in the database - */ -class client { - /** - * @var pdo $pdo The PDO class for database communication - * @var int $id The id of the client - * @var string $name The name of the client - */ - protected $pdo, $id, $name; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the client to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the client could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."client` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The client with id '$id' could not be found."); - } - $client = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $client['id']; - $this->name = $client['name']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the client - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the name of the client - * - * @return string The name - */ - public function getName() { - return $this->name; - } - - /** - * Set the name of the client - * - * @param string $name The new name for the client - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setName($name) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."client` SET `name`=? WHERE `id`=?"); - $stmt->execute(array($name, $this->id)); - if ($stmt->rowCount() == 1) { - $this->name = $name; - return true; - } else { - return false; - } - } - - /** - * Get all contact ids for this client - * - * @see client::getContacts() This funtion returns instances of the contact class instead of just the ids - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public function getContactIds() { - $ids = array(); - $contacts = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."contact` WHERE `clientId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); - foreach ($contacts as $contact) { - $ids[] = $contact['id']; - } - return $ids; - } - - /** - * Get all contacts for this client - * - * @see client::getContactIds() This function returns just the ids of the contacts, and not instances of the contact class - * - * @throws PDOException If something went wrong with the database - * - * @return contact[] An array indexed by id of instances of the contact class - */ - public function getContacts() { - $ids = $this->getContactIds(); - $contacts = array(); - foreach ($ids as $id) { - $contacts[$id] = new contact($this->pdo, $id); - } - return $contacts; - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Remove this client from the database - * - * If this doesn't succeed (i.e. false is returned), that means the client was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."client` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } - - /** - * Make a new contact for this client - * - * @param string $name The name for this contact - * @param string $email The email for this contact - * @param string $address The first address line of this contact (normally street and house number) - * @param string $address_2 The second address line of this contact - * @param string $postal_code The postal code for this contact - * @param string $city The city for this contact - * @param string $state The state for this contact - * @param string $country The country for this contact - * - * @throws PDOException If something went wrong with the database - * @throws Exception If there was a problem with the input - * - * @return contact A new instance of the contact class containing the new contact - */ - public function createContact($name, $email, $address, $address_2, $postal_code, $city, $country) { - $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."contact` (`clientId`,`name`,`email`,`address`,`address_2`,`postal_code`,`city`,`country`) VALUES (?,?,?,?,?,?,?,?)"); - $stmt->execute(array( - $this->id, - $name, - $email, - $address, - $address_2, - $postal_code, - $city, - $country - )); - if ($stmt->rowCount() == 1) { - return new contact($this->pdo, $this->pdo->lastInsertId()); - } else { - $error = $stmt->errorInfo(); - throw new Exception($error[2]); - } - } -} \ No newline at end of file diff --git a/classes/client.php b/classes/client.php new file mode 100644 index 0000000..1b45bae --- /dev/null +++ b/classes/client.php @@ -0,0 +1,195 @@ +. + */ + +/** + * An interface to the client table in the database + */ +class client { + /** + * @var pdo $pdo The PDO class for database communication + * @var int $id The id of the client + * @var string $name The name of the client + */ + protected $pdo, $id, $name; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the client to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the client could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."client` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The client with id '$id' could not be found."); + } + $client = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $client['id']; + $this->name = $client['name']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the client + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the name of the client + * + * @return string The name + */ + public function getName() { + return $this->name; + } + + /** + * Set the name of the client + * + * @param string $name The new name for the client + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setName($name) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."client` SET `name`=? WHERE `id`=?"); + $stmt->execute(array($name, $this->id)); + if ($stmt->rowCount() == 1) { + $this->name = $name; + return true; + } else { + return false; + } + } + + /** + * Get all contact ids for this client + * + * @see client::getContacts() This funtion returns instances of the contact class instead of just the ids + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public function getContactIds() { + $ids = array(); + $contacts = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."contact` WHERE `clientId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); + foreach ($contacts as $contact) { + $ids[] = $contact['id']; + } + return $ids; + } + + /** + * Get all contacts for this client + * + * @see client::getContactIds() This function returns just the ids of the contacts, and not instances of the contact class + * + * @throws PDOException If something went wrong with the database + * + * @return contact[] An array indexed by id of instances of the contact class + */ + public function getContacts() { + $ids = $this->getContactIds(); + $contacts = array(); + foreach ($ids as $id) { + $contacts[$id] = new contact($this->pdo, $id); + } + return $contacts; + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Remove this client from the database + * + * If this doesn't succeed (i.e. false is returned), that means the client was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."client` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } + + /** + * Make a new contact for this client + * + * @param string $name The name for this contact + * @param string $email The email for this contact + * @param string $address The first address line of this contact (normally street and house number) + * @param string $address_2 The second address line of this contact + * @param string $postal_code The postal code for this contact + * @param string $city The city for this contact + * @param string $state The state for this contact + * @param string $country The country for this contact + * + * @throws PDOException If something went wrong with the database + * @throws Exception If there was a problem with the input + * + * @return contact A new instance of the contact class containing the new contact + */ + public function createContact($name, $email, $address, $address_2, $postal_code, $city, $country) { + $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."contact` (`clientId`,`name`,`email`,`address`,`address_2`,`postal_code`,`city`,`country`) VALUES (?,?,?,?,?,?,?,?)"); + $stmt->execute(array( + $this->id, + $name, + $email, + $address, + $address_2, + $postal_code, + $city, + $country + )); + if ($stmt->rowCount() == 1) { + return new contact($this->pdo, $this->pdo->lastInsertId()); + } else { + $error = $stmt->errorInfo(); + throw new Exception($error[2]); + } + } +} \ No newline at end of file diff --git a/classes/constants.class.php b/classes/constants.class.php deleted file mode 100644 index 09b9f98..0000000 --- a/classes/constants.class.php +++ /dev/null @@ -1,74 +0,0 @@ -. - */ - -/** - * A class for some constants - */ -class constants { - /** @const db_prefix A prefix to add to the tables in the database (leave empty for none) */ - const db_prefix = ''; - - /** @const files_folder The folder to store all files (appendices, invoices, etc.) in; with a trailing slash */ - const files_folder = '/var/www/localhost/BusinessAdmin/files/'; - /** @const files_folder_external The external URI to this folder; with a trailing slash */ - const files_folder_external = 'http://localhost/BusinessAdmin/files/'; - /** @const files_folder_trash The folder inside files_folder to use a trash, without any trailing slashes */ - const files_folder_trash = 'trash'; - - /** @const url_external The external URI to this folder; with a trailing slash */ - const url_external = 'http://localhost/BusinessAdmin/'; - /** @const url_internal The URI without the domain name; with a slash at the beginning but not at the end */ - const url_internal = '/BusinessAdmin'; - - /** @const my_name Name of this control panel */ - const my_name = 'BusinessAdmin'; - - /** - * @const invoice_name Your name or the name of your business - * @const invoice_address_1 First address line - * @const invoice_address_2 Second address line - * @const invoice_address_3 Third address line - * @const invoice_tax_nr Your tax number - * @const invoice_iban Your IBAN number - * @const invoice_bic The BIC code of your bank - * @const invoice_tel_nr Your telephone number - * @const invoice_email Your email address - * @const invoice_valuta The valuta symbol (will be placed in front of amounts). You can use a symbol like $ or a code like USD - */ - const invoice_name = 'BusinessAdmin'; - const invoice_address_1 = 'My Street 1'; - const invoice_address_2 = '12345 My City'; - const invoice_address_3 = 'My Country'; - const invoice_tax_nr = 'XX123456789A00'; - const invoice_iban = 'XX00 ABCD 1234 5678 90'; - const invoice_bic = 'XXXX XXXX'; - const invoice_tel_nr = '+31 6 1234 5678'; - const invoice_email = 'my-email@domain.tld'; - const invoice_valuta = '€'; - - /** @const fa_valuta see http://fontawesome.io/icons/#currency; the fa- postfix for valuta */ - const fa_valuta = 'eur'; - - /** @const version Version of BusinessAdmin. Don't change this yourself! */ - const version = '0.3'; -} diff --git a/classes/constants.php b/classes/constants.php new file mode 100644 index 0000000..09b9f98 --- /dev/null +++ b/classes/constants.php @@ -0,0 +1,74 @@ +. + */ + +/** + * A class for some constants + */ +class constants { + /** @const db_prefix A prefix to add to the tables in the database (leave empty for none) */ + const db_prefix = ''; + + /** @const files_folder The folder to store all files (appendices, invoices, etc.) in; with a trailing slash */ + const files_folder = '/var/www/localhost/BusinessAdmin/files/'; + /** @const files_folder_external The external URI to this folder; with a trailing slash */ + const files_folder_external = 'http://localhost/BusinessAdmin/files/'; + /** @const files_folder_trash The folder inside files_folder to use a trash, without any trailing slashes */ + const files_folder_trash = 'trash'; + + /** @const url_external The external URI to this folder; with a trailing slash */ + const url_external = 'http://localhost/BusinessAdmin/'; + /** @const url_internal The URI without the domain name; with a slash at the beginning but not at the end */ + const url_internal = '/BusinessAdmin'; + + /** @const my_name Name of this control panel */ + const my_name = 'BusinessAdmin'; + + /** + * @const invoice_name Your name or the name of your business + * @const invoice_address_1 First address line + * @const invoice_address_2 Second address line + * @const invoice_address_3 Third address line + * @const invoice_tax_nr Your tax number + * @const invoice_iban Your IBAN number + * @const invoice_bic The BIC code of your bank + * @const invoice_tel_nr Your telephone number + * @const invoice_email Your email address + * @const invoice_valuta The valuta symbol (will be placed in front of amounts). You can use a symbol like $ or a code like USD + */ + const invoice_name = 'BusinessAdmin'; + const invoice_address_1 = 'My Street 1'; + const invoice_address_2 = '12345 My City'; + const invoice_address_3 = 'My Country'; + const invoice_tax_nr = 'XX123456789A00'; + const invoice_iban = 'XX00 ABCD 1234 5678 90'; + const invoice_bic = 'XXXX XXXX'; + const invoice_tel_nr = '+31 6 1234 5678'; + const invoice_email = 'my-email@domain.tld'; + const invoice_valuta = '€'; + + /** @const fa_valuta see http://fontawesome.io/icons/#currency; the fa- postfix for valuta */ + const fa_valuta = 'eur'; + + /** @const version Version of BusinessAdmin. Don't change this yourself! */ + const version = '0.3'; +} diff --git a/classes/contact.class.php b/classes/contact.class.php deleted file mode 100644 index f920f00..0000000 --- a/classes/contact.class.php +++ /dev/null @@ -1,378 +0,0 @@ -. - */ - -/** - * An interface to the contact table in the database - */ -class contact { - /** - * @var PDO $pdo The PDO class for database communication - * @var int $id The id of the contact - * @var int $clientId The id of the client the contact is linked to - * @var string $name The name of the contact - * @var string $email The email address of the contact - * @var string $address The first address line (normally street and house number) of the contact - * @var string $address_2 The second address line (can be null) - * @var string $postal_code The postal code of the contact - * @var string $city The city of the contact - * @var string $country The country of the contact - * @var string $language The language of the contact - */ - protected $pdo, $id, $clientId, $name, $email, $address, $postal_code, $city, $country, $language; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the contact to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the contact could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."contact` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The contact with id '$id' could not be found."); - } - $contact = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $contact['id']; - $this->clientId = $contact['clientId']; - $this->name = $contact['name']; - $this->email = $contact['email']; - $this->address = $contact['address']; - $this->address_2 = $contact['address_2']; - $this->postal_code = $contact['postal_code']; - $this->city = $contact['city']; - $this->country = $contact['country']; - $this->language = $contact['language']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the contact - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the ID of the client that this contact is linked to - * - * @return int The ID - */ - public function getClientId() { - return $this->clientId; - } - - /** - * Get the client that this contact is linked to - * - * @return client The client - */ - public function getClient() { - return new client($this->pdo, $this->clientId); - } - - /** - * Get the name of the contact - * - * @return string The name - */ - public function getName() { - return $this->name; - } - - /** - * Set the name of the contact - * - * @param string $name The new name for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setName($name) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `name`=? WHERE `id`=?"); - $stmt->execute(array($name, $this->id)); - if ($stmt->rowCount() == 1) { - $this->name = $name; - return true; - } else { - return false; - } - } - - /** - * Get the email of the contact - * - * @return string The email - */ - public function getEmail() { - return $this->email; - } - - /** - * Set the email of the contact - * - * @param string $email The new email for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setEmail($email) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `email`=? WHERE `id`=?"); - $stmt->execute(array($email, $this->id)); - if ($stmt->rowCount() == 1) { - $this->email = $email; - return true; - } else { - return false; - } - } - - /** - * Get the first address line of the contact - * - * @return string The address - */ - public function getAddress() { - return $this->address; - } - - /** - * Set the first address line of the contact - * - * @param string $address The new address for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setAddress($address) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `address`=? WHERE `id`=?"); - $stmt->execute(array($address, $this->id)); - if ($stmt->rowCount() == 1) { - $this->address = $address; - return true; - } else { - return false; - } - } - - /** - * Get the second address line of the contact - * - * @return string The address - */ - public function getAddress_2() { - return $this->address_2; - } - - /** - * Set the second address line of the contact - * - * @param string $address_2 The new address for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setAddress_2($address_2) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `address_2`=? WHERE `id`=?"); - $stmt->execute(array($address_2, $this->id)); - if ($stmt->rowCount() == 1) { - $this->address_2 = $address_2; - return true; - } else { - return false; - } - } - - /** - * Get the postal_code of the contact - * - * @return string The postal_code - */ - public function getPostalCode() { - return $this->postal_code; - } - - /** - * Set the postal code of the contact - * - * @param $postal_code string The new postal code for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setPostalCode($postal_code) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `postal_code`=? WHERE `id`=?"); - $stmt->execute(array($postal_code, $this->id)); - if ($stmt->rowCount() == 1) { - return true; - $this->postal_code = $postal_code; - } else { - return false; - } - } - - /** - * Get the city of the contact - * - * @return string The city - */ - public function getCity() { - return $this->city; - } - - /** - * Set the city of the contact - * - * @param string $city The new city for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setCity($city) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `city`=? WHERE `id`=?"); - $stmt->execute(array($city, $this->id)); - if ($stmt->rowCount() == 1) { - $this->city = $city; - return true; - } else { - return false; - } - } - - /** - * Get the country of the contact - * - * @return string The country - */ - public function getCountry() { - return $this->country; - } - - /** - * Set the country of the contact - * - * @param string $country The new country for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setCountry($country) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `country`=? WHERE `id`=?"); - $stmt->execute(array($country, $this->id)); - if ($stmt->rowCount() == 1) { - $this->country = $country; - return true; - } else { - return false; - } - } - - /** - * Get the language of the contact - * - * @return string The language - */ - public function getLanguage() { - return $this->language; - } - - /** - * Set the language of the contact - * - * @param string $language The new language for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setLanguage($language) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `language`=? WHERE `id`=?"); - $stmt->execute(array($language, $this->id)); - if ($stmt->rowCount() == 1) { - $this->language = $language; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Remove this contact from the database - * - * If this doesn't succeed (i.e. false is returned), that means the contact was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."contact` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } - - /** - * Make a new offer for this contact - * - * @throws PDOException If something went wrong with the database - * @throws Exception If there was a problem with the input - * - * @return offer A new instance of the offer class containing the new offer - */ - public function createOffer() { - $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."offer` (`contactId`) VALUES (?)"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() == 1) { - return new offer($this->pdo, $this->pdo->lastInsertId()); - } else { - $error = $stmt->errorInfo(); - throw new Exception($error[2]); - } - } -} \ No newline at end of file diff --git a/classes/contact.php b/classes/contact.php new file mode 100644 index 0000000..f920f00 --- /dev/null +++ b/classes/contact.php @@ -0,0 +1,378 @@ +. + */ + +/** + * An interface to the contact table in the database + */ +class contact { + /** + * @var PDO $pdo The PDO class for database communication + * @var int $id The id of the contact + * @var int $clientId The id of the client the contact is linked to + * @var string $name The name of the contact + * @var string $email The email address of the contact + * @var string $address The first address line (normally street and house number) of the contact + * @var string $address_2 The second address line (can be null) + * @var string $postal_code The postal code of the contact + * @var string $city The city of the contact + * @var string $country The country of the contact + * @var string $language The language of the contact + */ + protected $pdo, $id, $clientId, $name, $email, $address, $postal_code, $city, $country, $language; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the contact to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the contact could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."contact` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The contact with id '$id' could not be found."); + } + $contact = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $contact['id']; + $this->clientId = $contact['clientId']; + $this->name = $contact['name']; + $this->email = $contact['email']; + $this->address = $contact['address']; + $this->address_2 = $contact['address_2']; + $this->postal_code = $contact['postal_code']; + $this->city = $contact['city']; + $this->country = $contact['country']; + $this->language = $contact['language']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the contact + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the ID of the client that this contact is linked to + * + * @return int The ID + */ + public function getClientId() { + return $this->clientId; + } + + /** + * Get the client that this contact is linked to + * + * @return client The client + */ + public function getClient() { + return new client($this->pdo, $this->clientId); + } + + /** + * Get the name of the contact + * + * @return string The name + */ + public function getName() { + return $this->name; + } + + /** + * Set the name of the contact + * + * @param string $name The new name for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setName($name) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `name`=? WHERE `id`=?"); + $stmt->execute(array($name, $this->id)); + if ($stmt->rowCount() == 1) { + $this->name = $name; + return true; + } else { + return false; + } + } + + /** + * Get the email of the contact + * + * @return string The email + */ + public function getEmail() { + return $this->email; + } + + /** + * Set the email of the contact + * + * @param string $email The new email for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setEmail($email) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `email`=? WHERE `id`=?"); + $stmt->execute(array($email, $this->id)); + if ($stmt->rowCount() == 1) { + $this->email = $email; + return true; + } else { + return false; + } + } + + /** + * Get the first address line of the contact + * + * @return string The address + */ + public function getAddress() { + return $this->address; + } + + /** + * Set the first address line of the contact + * + * @param string $address The new address for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setAddress($address) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `address`=? WHERE `id`=?"); + $stmt->execute(array($address, $this->id)); + if ($stmt->rowCount() == 1) { + $this->address = $address; + return true; + } else { + return false; + } + } + + /** + * Get the second address line of the contact + * + * @return string The address + */ + public function getAddress_2() { + return $this->address_2; + } + + /** + * Set the second address line of the contact + * + * @param string $address_2 The new address for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setAddress_2($address_2) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `address_2`=? WHERE `id`=?"); + $stmt->execute(array($address_2, $this->id)); + if ($stmt->rowCount() == 1) { + $this->address_2 = $address_2; + return true; + } else { + return false; + } + } + + /** + * Get the postal_code of the contact + * + * @return string The postal_code + */ + public function getPostalCode() { + return $this->postal_code; + } + + /** + * Set the postal code of the contact + * + * @param $postal_code string The new postal code for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setPostalCode($postal_code) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `postal_code`=? WHERE `id`=?"); + $stmt->execute(array($postal_code, $this->id)); + if ($stmt->rowCount() == 1) { + return true; + $this->postal_code = $postal_code; + } else { + return false; + } + } + + /** + * Get the city of the contact + * + * @return string The city + */ + public function getCity() { + return $this->city; + } + + /** + * Set the city of the contact + * + * @param string $city The new city for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setCity($city) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `city`=? WHERE `id`=?"); + $stmt->execute(array($city, $this->id)); + if ($stmt->rowCount() == 1) { + $this->city = $city; + return true; + } else { + return false; + } + } + + /** + * Get the country of the contact + * + * @return string The country + */ + public function getCountry() { + return $this->country; + } + + /** + * Set the country of the contact + * + * @param string $country The new country for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setCountry($country) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `country`=? WHERE `id`=?"); + $stmt->execute(array($country, $this->id)); + if ($stmt->rowCount() == 1) { + $this->country = $country; + return true; + } else { + return false; + } + } + + /** + * Get the language of the contact + * + * @return string The language + */ + public function getLanguage() { + return $this->language; + } + + /** + * Set the language of the contact + * + * @param string $language The new language for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setLanguage($language) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `language`=? WHERE `id`=?"); + $stmt->execute(array($language, $this->id)); + if ($stmt->rowCount() == 1) { + $this->language = $language; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Remove this contact from the database + * + * If this doesn't succeed (i.e. false is returned), that means the contact was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."contact` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } + + /** + * Make a new offer for this contact + * + * @throws PDOException If something went wrong with the database + * @throws Exception If there was a problem with the input + * + * @return offer A new instance of the offer class containing the new offer + */ + public function createOffer() { + $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."offer` (`contactId`) VALUES (?)"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() == 1) { + return new offer($this->pdo, $this->pdo->lastInsertId()); + } else { + $error = $stmt->errorInfo(); + throw new Exception($error[2]); + } + } +} \ No newline at end of file diff --git a/classes/correspondence.class.php b/classes/correspondence.class.php deleted file mode 100644 index 8330ea0..0000000 --- a/classes/correspondence.class.php +++ /dev/null @@ -1,313 +0,0 @@ -. - */ - -require_once('fpdf.php'); - -/** - * An extension of FPDF to generate personalized correspondence PDFs - */ -class correspondence extends FPDF { - /** - * @var $contact Holds the contact this correspondence will be sent to - * @var $language Holds the language this correspondence should be sent in - */ - var $contact, $language; - - /** - * If you'd want, you could change these constants to encode an RGB colour for headings in your PDFs - */ - const HEAD_RED = 0; - const HEAD_GREEN = 0; - const HEAD_BLUE = 0; - - /** - * Array holding the translations - * - * @see _() A function to translate - */ - protected static $translations = array( - 'adres' => array( - 'en' => 'Address', - 'nl' => 'Adres'), - 'amount' => array( - 'en' => 'Amount', - 'nl' => 'Subtotaal'), - 'amount-due' => array( - 'en' => 'Total amount due', - 'nl' => 'Te voldoen'), - 'biccode' => array( - 'en' => 'The BIC code of our bank is %%.', - 'nl' => 'De BIC-code van de bank is %%.'), - 'btwnr' => array( - 'en' => 'VAT nr', - 'nl' => 'BTW nr'), - 'description' => array( - 'en' => 'Description', - 'nl' => 'Omschrijving'), - 'due-date' => array( - 'en' => 'Due date', - 'nl' => 'Vervaldatum'), - 'email' => array( - 'en' => 'Email', - 'nl' => 'Email'), - 'iban' => array( - 'en' => 'IBAN', - 'nl' => 'IBAN'), - 'invoice' => array( - 'en' => 'Invoice', - 'nl' => 'Factuur'), - 'invoice-date' => array( - 'en' => 'Invoice date', - 'nl' => 'Factuurdatum'), - 'invoice-nr' => array( - 'en' => 'Invoice number', - 'nl' => 'Factuurnummer'), - 'price-excl' => array( - 'en' => 'Price excl.', - 'nl' => 'Prijs excl.'), - 'price-incl' => array( - 'en' => 'Price incl.', - 'nl' => 'Prijs incl.'), - 'request' => array( - 'en' => 'You are kindly requested to transfer the total amount before the due date to the provided IBAN nr.', - 'nl' => 'U wordt vriendelijk verzocht het te voldoen bedrag voor de vervaldatum van de factuur over te maken naar opgegeven IBAN-nummer.'), - 'tel-nr' => array( - 'en' => 'Tel.', - 'nl' => 'Tel.'), - 'total' => array( - 'en' => 'Total', - 'nl' => 'Totaal'), - 'vat' => array( - 'en' => 'VAT', - 'nl' => 'BTW'), - ); - - /** - * @var $page_height The height of a page in millimeters - * @var $margin_bottom The bottom margin in millimeters - */ - protected static $page_height = 297; // A4 - protected static $margin_bottom = 30; - - /** - * Translate a string - * - * @see $translations The array holding the translations - * - * @param string $key The string to translate - * @param string $lang The language to translate to (two-letter code) - * - * @return string The translated string - */ - public function _($key) { - if (!array_key_exists($key, self::$translations)) - return $key; - return self::$translations[$key][$this->language]; - } - - /** - * Create a new PDF - * - * @param string $orientation See the FPDF class specs - * @param string $unit See the FPDF class specs - * @param string $size See the FPDF class specs - */ - function __construct() { - $this->FPDF('P','mm','A4'); - - $this->SetMargins(30,20,20); - $this->SetAuthor(constants::invoice_name); - $this->SetCreator('BusinessAdmin Correspondence Generator'); - $this->SetDisplayMode('fullpage','continuous'); - } - - /** - * Workaround for euro signs - * - * Euro signs in FPDF should be chr(128). Other signs don't have to be changed. - * - * @return a valuta symbol that can be used in FPDF - */ - public static function valuta() { - switch (constants::invoice_valuta) { - case '€': - return chr(128); - default: - return constants::invoice_valuta; - } - } - - /** - * Set the language of the correspondence (used to translate stuff) - * - * @param string $lang The language, two letter code ('en', 'nl', ...) - */ - function SetLangauge($lang) { - $supported = array('nl', 'en'); - if (!in_array($lang, $supported)) { - throw new Exception("Language not supported"); - } else { - $this->language = $lang; - } - } - - /** - * Set the contact to whom this correspondence will be sent (used for the address) - * - * @param contact $contact The contact - */ - function SetContact($contact) { - $this->contact = $contact; - - $this->language = $contact->getLanguage(); - } - - /** - * Makes a header with your details and the address of the contact - */ - function CorrespondenceHeader() { - if (file_exists(constants::files_folder . 'logo-correspondence.png')) { - $this->Image(constants::files_folder . 'logo-correspondence.png',30,20,50); - } - - $this->SetFont('Helvetica','',7); - $this->Cell(110,20); - $this->Cell(12,1,' ','T'); - $this->Cell(2,1); - $this->Cell(35,1,' ','T'); - $this->Ln(); - - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5,$this->_('adres'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('',''); - $this->Cell(35,3.5, constants::invoice_name); - $this->Ln(); - - $this->Cell(124,3.5); - $this->Cell(35,3.5, constants::invoice_address_1); - $this->Ln(); - $this->Cell(124,3.5); - $this->Cell(35,3.5, constants::invoice_address_2); - $this->Ln(); - $this->Cell(124,3.5); - $this->Cell(35,3.5, constants::invoice_address_3); - $this->Ln(); - $this->Cell(160,1.5); - $this->Ln(); - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5,$this->_('btwnr'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('',''); - $this->Cell(35,3.5, constants::invoice_tax_nr); - $this->Ln(); - $this->Cell(160,1.5); - $this->Ln(); - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5, $this->_('iban'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('',''); - $this->Cell(35,3.5, constants::invoice_iban); - $this->Ln(); - $this->Cell(160,1.5); - $this->Ln(); - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5, $this->_('tel-nr'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('','',7); - $this->Cell(35,3.5, constants::invoice_tel_nr); - $this->Ln(); - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5, $this->_('email'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('',''); - $this->Cell(35,3.5, constants::invoice_email); - $this->Ln(); - $this->Cell(110,1); - $this->Cell(12,1,' ','B'); - $this->Cell(2,1); - $this->Cell(35,1,' ','B'); - $this->Ln(); - $this->Cell(160,15); - $this->Ln(); - - $this->SetFont('','',11); - $this->SetXY(30,56.5); - $this->Cell(90,5.5,utf8_decode($this->contact->getName())); - $this->Ln(); - $this->SetXY(30,61.5); - $this->Cell(90,5.5,utf8_decode($this->contact->getAddress())); - $this->Ln(); - $this->SetXY(30,66.5); - $this->Cell(90,5.5,utf8_decode($this->contact->getPostalCode().' '.$this->contact->getCity())); - $this->Ln(); - $this->SetXY(30,71.5); - $this->Cell(90,5.5,utf8_decode($this->contact->getCountry())); - $this->Ln(); - } - - /** - * Put PDF information - */ - function _putinfo() - { - $this->_out('/Producer '.$this->_textstring('BusinessAdmin Correspondence Generator')); - if(!empty($this->title)) - $this->_out('/Title '.$this->_textstring($this->title)); - if(!empty($this->subject)) - $this->_out('/Subject '.$this->_textstring($this->subject)); - if(!empty($this->author)) - $this->_out('/Author '.$this->_textstring($this->author)); - if(!empty($this->keywords)) - $this->_out('/Keywords '.$this->_textstring($this->keywords)); - if(!empty($this->creator)) - $this->_out('/Creator '.$this->_textstring($this->creator)); - $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis'))); - } - - /** - * Have we reached the bottom of the page yet? - * - * @return bool - */ - public function endOfPage() { - return ($this->GetY() > self::$page_height - self::$margin_bottom); - } - - /** - * Start a new page if we're on the end - */ - public function addPageIfOnEnd() { - if ($this->endOfPage()) { - $this->Ln(); - $this->AddPage(); - $this->Cell(100, 5, ''); // blank line - $this->Ln(); - } - } -} \ No newline at end of file diff --git a/classes/correspondence.php b/classes/correspondence.php new file mode 100644 index 0000000..96c0863 --- /dev/null +++ b/classes/correspondence.php @@ -0,0 +1,311 @@ +. + */ + +/** + * An extension of FPDF to generate personalized correspondence PDFs + */ +class correspondence extends FPDF { + /** + * @var $contact Holds the contact this correspondence will be sent to + * @var $language Holds the language this correspondence should be sent in + */ + var $contact, $language; + + /** + * If you'd want, you could change these constants to encode an RGB colour for headings in your PDFs + */ + const HEAD_RED = 0; + const HEAD_GREEN = 0; + const HEAD_BLUE = 0; + + /** + * Array holding the translations + * + * @see _() A function to translate + */ + protected static $translations = array( + 'adres' => array( + 'en' => 'Address', + 'nl' => 'Adres'), + 'amount' => array( + 'en' => 'Amount', + 'nl' => 'Subtotaal'), + 'amount-due' => array( + 'en' => 'Total amount due', + 'nl' => 'Te voldoen'), + 'biccode' => array( + 'en' => 'The BIC code of our bank is %%.', + 'nl' => 'De BIC-code van de bank is %%.'), + 'btwnr' => array( + 'en' => 'VAT nr', + 'nl' => 'BTW nr'), + 'description' => array( + 'en' => 'Description', + 'nl' => 'Omschrijving'), + 'due-date' => array( + 'en' => 'Due date', + 'nl' => 'Vervaldatum'), + 'email' => array( + 'en' => 'Email', + 'nl' => 'Email'), + 'iban' => array( + 'en' => 'IBAN', + 'nl' => 'IBAN'), + 'invoice' => array( + 'en' => 'Invoice', + 'nl' => 'Factuur'), + 'invoice-date' => array( + 'en' => 'Invoice date', + 'nl' => 'Factuurdatum'), + 'invoice-nr' => array( + 'en' => 'Invoice number', + 'nl' => 'Factuurnummer'), + 'price-excl' => array( + 'en' => 'Price excl.', + 'nl' => 'Prijs excl.'), + 'price-incl' => array( + 'en' => 'Price incl.', + 'nl' => 'Prijs incl.'), + 'request' => array( + 'en' => 'You are kindly requested to transfer the total amount before the due date to the provided IBAN nr.', + 'nl' => 'U wordt vriendelijk verzocht het te voldoen bedrag voor de vervaldatum van de factuur over te maken naar opgegeven IBAN-nummer.'), + 'tel-nr' => array( + 'en' => 'Tel.', + 'nl' => 'Tel.'), + 'total' => array( + 'en' => 'Total', + 'nl' => 'Totaal'), + 'vat' => array( + 'en' => 'VAT', + 'nl' => 'BTW'), + ); + + /** + * @var $page_height The height of a page in millimeters + * @var $margin_bottom The bottom margin in millimeters + */ + protected static $page_height = 297; // A4 + protected static $margin_bottom = 30; + + /** + * Translate a string + * + * @see $translations The array holding the translations + * + * @param string $key The string to translate + * @param string $lang The language to translate to (two-letter code) + * + * @return string The translated string + */ + public function _($key) { + if (!array_key_exists($key, self::$translations)) + return $key; + return self::$translations[$key][$this->language]; + } + + /** + * Create a new PDF + * + * @param string $orientation See the FPDF class specs + * @param string $unit See the FPDF class specs + * @param string $size See the FPDF class specs + */ + function __construct() { + $this->FPDF('P','mm','A4'); + + $this->SetMargins(30,20,20); + $this->SetAuthor(constants::invoice_name); + $this->SetCreator('BusinessAdmin Correspondence Generator'); + $this->SetDisplayMode('fullpage','continuous'); + } + + /** + * Workaround for euro signs + * + * Euro signs in FPDF should be chr(128). Other signs don't have to be changed. + * + * @return a valuta symbol that can be used in FPDF + */ + public static function valuta() { + switch (constants::invoice_valuta) { + case '€': + return chr(128); + default: + return constants::invoice_valuta; + } + } + + /** + * Set the language of the correspondence (used to translate stuff) + * + * @param string $lang The language, two letter code ('en', 'nl', ...) + */ + function SetLangauge($lang) { + $supported = array('nl', 'en'); + if (!in_array($lang, $supported)) { + throw new Exception("Language not supported"); + } else { + $this->language = $lang; + } + } + + /** + * Set the contact to whom this correspondence will be sent (used for the address) + * + * @param contact $contact The contact + */ + function SetContact($contact) { + $this->contact = $contact; + + $this->language = $contact->getLanguage(); + } + + /** + * Makes a header with your details and the address of the contact + */ + function CorrespondenceHeader() { + if (file_exists(constants::files_folder . 'logo-correspondence.png')) { + $this->Image(constants::files_folder . 'logo-correspondence.png',30,20,50); + } + + $this->SetFont('Helvetica','',7); + $this->Cell(110,20); + $this->Cell(12,1,' ','T'); + $this->Cell(2,1); + $this->Cell(35,1,' ','T'); + $this->Ln(); + + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5,$this->_('adres'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('',''); + $this->Cell(35,3.5, constants::invoice_name); + $this->Ln(); + + $this->Cell(124,3.5); + $this->Cell(35,3.5, constants::invoice_address_1); + $this->Ln(); + $this->Cell(124,3.5); + $this->Cell(35,3.5, constants::invoice_address_2); + $this->Ln(); + $this->Cell(124,3.5); + $this->Cell(35,3.5, constants::invoice_address_3); + $this->Ln(); + $this->Cell(160,1.5); + $this->Ln(); + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5,$this->_('btwnr'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('',''); + $this->Cell(35,3.5, constants::invoice_tax_nr); + $this->Ln(); + $this->Cell(160,1.5); + $this->Ln(); + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5, $this->_('iban'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('',''); + $this->Cell(35,3.5, constants::invoice_iban); + $this->Ln(); + $this->Cell(160,1.5); + $this->Ln(); + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5, $this->_('tel-nr'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('','',7); + $this->Cell(35,3.5, constants::invoice_tel_nr); + $this->Ln(); + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5, $this->_('email'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('',''); + $this->Cell(35,3.5, constants::invoice_email); + $this->Ln(); + $this->Cell(110,1); + $this->Cell(12,1,' ','B'); + $this->Cell(2,1); + $this->Cell(35,1,' ','B'); + $this->Ln(); + $this->Cell(160,15); + $this->Ln(); + + $this->SetFont('','',11); + $this->SetXY(30,56.5); + $this->Cell(90,5.5,utf8_decode($this->contact->getName())); + $this->Ln(); + $this->SetXY(30,61.5); + $this->Cell(90,5.5,utf8_decode($this->contact->getAddress())); + $this->Ln(); + $this->SetXY(30,66.5); + $this->Cell(90,5.5,utf8_decode($this->contact->getPostalCode().' '.$this->contact->getCity())); + $this->Ln(); + $this->SetXY(30,71.5); + $this->Cell(90,5.5,utf8_decode($this->contact->getCountry())); + $this->Ln(); + } + + /** + * Put PDF information + */ + function _putinfo() + { + $this->_out('/Producer '.$this->_textstring('BusinessAdmin Correspondence Generator')); + if(!empty($this->title)) + $this->_out('/Title '.$this->_textstring($this->title)); + if(!empty($this->subject)) + $this->_out('/Subject '.$this->_textstring($this->subject)); + if(!empty($this->author)) + $this->_out('/Author '.$this->_textstring($this->author)); + if(!empty($this->keywords)) + $this->_out('/Keywords '.$this->_textstring($this->keywords)); + if(!empty($this->creator)) + $this->_out('/Creator '.$this->_textstring($this->creator)); + $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis'))); + } + + /** + * Have we reached the bottom of the page yet? + * + * @return bool + */ + public function endOfPage() { + return ($this->GetY() > self::$page_height - self::$margin_bottom); + } + + /** + * Start a new page if we're on the end + */ + public function addPageIfOnEnd() { + if ($this->endOfPage()) { + $this->Ln(); + $this->AddPage(); + $this->Cell(100, 5, ''); // blank line + $this->Ln(); + } + } +} diff --git a/classes/discount.class.php b/classes/discount.class.php deleted file mode 100644 index 71aa370..0000000 --- a/classes/discount.class.php +++ /dev/null @@ -1,285 +0,0 @@ -. - */ - -/** - * An interface to the discount table in the database - */ -class discount { - /** - * @var pdo $pdo The PDO class for database communication - * @var int $id The id of the discount - * @var int $offerId The id of the offer this discount is linked to - * @var string $title The title of the discount - * @var string $description The description of the discount - * @var float $value The actual discount - * @var float $vat The percentage of VAT to calculate on this discount - */ - protected $pdo, $offerId, $id, $title, $description, $value, $vat; - - const SUBTOTAL = 1; - const VAT = 2; - const TOTAL = 3; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the discount to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the discount could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."discount` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The discount with id '$id' could not be found."); - } - $discount = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $discount['id']; - $this->offerId = $discount['offerId']; - $this->title = $discount['title']; - $this->description = $discount['description']; - $this->value = $discount['value']; - $this->vat = $discount['VAT_percentage']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the discount - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the ID of the offer that this discount is linked to - * - * @return int The ID - */ - public function getOfferId() { - return $this->offerId; - } - - /** - * Get the offer that this discount is linked to - * - * @return offer The offer - */ - public function getOffer() { - return new offer($this->pdo, $this->offerId); - } - - /** - * Get the title of the discount - * - * @return string The title - */ - public function getTitle() { - return $this->title; - } - - /** - * Set the title of the discount - * - * @param string $title The new title for the discount - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setTitle($title) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `title`=? WHERE `id`=?"); - $stmt->execute(array($title, $this->id)); - if ($stmt->rowCount() == 1) { - $this->title = $title; - return true; - } else { - return false; - } - } - - /** - * Get the description of the discount - * - * @param bool $parseMarkdown Whether or not to parse markdown - * - * @return string The description - */ - public function getDescription($parseMarkdown = true) { - if ($parseMarkdown) { - $pd = new Parsedown; - return $pd->text($this->description); - } else { - return $this->description; - } - } - - /** - * Set the description of the discount - * - * @param string $description The new description for the discount - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setDescription($description) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `description`=? WHERE `id`=?"); - $stmt->execute(array($description, $this->id)); - if ($stmt->rowCount() == 1) { - $this->description = $description; - return true; - } else { - return false; - } - } - - /** - * Get the value of the discount - * - * @return float The value - */ - public function getValue() { - return $this->value; - } - - /** - * Set the value of the discount - * - * @param float $value The new value for the discount - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setValue($value) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `value`=? WHERE `id`=?"); - $stmt->execute(array($value, $this->id)); - if ($stmt->rowCount() == 1) { - $this->value = $value; - return true; - } else { - return false; - } - } - - /** - * Get the VAT percentage of the discount - * - * @return float The VAT percentage - */ - public function getVAT() { - return $this->vat; - } - - /** - * Set the VAT percentage of the discount - * - * @param float $vat The new VAT percentage for the discount - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setVAT($vat) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `VAT_percentage`=? WHERE `id`=?"); - $stmt->execute(array($vat, $this->id)); - if ($stmt->rowCount() == 1) { - $this->vat = $vat; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Calculate useful numbers about the discount - * - * Subtotal: value - * - * VAT: subtotal \* VAT_percentage - * - * Total: subtotal + VAT - * - * @param int $what Any of discount::SUBTOTAL, discount::VAT, discount::TOTAL - * @param int $round How many decimals to round on - * @param bool $format Whether to format the number nicely (for output) or not (for calculations) - * - * @throws PDOException If something went wrong with the database - * - * @return float|bool The calculated value rounded on $round decimals, or false when the input is incorrect - */ - public function calculate($what = self::TOTAL, $round = 2, $format = true) { - $return = 0; - switch ($what) { - case self::SUBTOTAL: - $return = - $this->value; - break; - case self::VAT: - $return = $this->calculate(self::SUBTOTAL, $round + 1, false) * $this->getVAT() / 100; - break; - case self::TOTAL: - $return = $this->calculate(self::SUBTOTAL, $round + 1, false) + $this->calculate(self::VAT, $round + 1, false); - break; - default: - return false; - } - if ($format) { - return number_format($return, $round); - } else { - return round($return, $round); - } - } - - /** - * Remove this discount from the database - * - * If this doesn't succeed (i.e. false is returned), that means the discount was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."discount` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } -} diff --git a/classes/discount.php b/classes/discount.php new file mode 100644 index 0000000..71aa370 --- /dev/null +++ b/classes/discount.php @@ -0,0 +1,285 @@ +. + */ + +/** + * An interface to the discount table in the database + */ +class discount { + /** + * @var pdo $pdo The PDO class for database communication + * @var int $id The id of the discount + * @var int $offerId The id of the offer this discount is linked to + * @var string $title The title of the discount + * @var string $description The description of the discount + * @var float $value The actual discount + * @var float $vat The percentage of VAT to calculate on this discount + */ + protected $pdo, $offerId, $id, $title, $description, $value, $vat; + + const SUBTOTAL = 1; + const VAT = 2; + const TOTAL = 3; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the discount to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the discount could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."discount` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The discount with id '$id' could not be found."); + } + $discount = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $discount['id']; + $this->offerId = $discount['offerId']; + $this->title = $discount['title']; + $this->description = $discount['description']; + $this->value = $discount['value']; + $this->vat = $discount['VAT_percentage']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the discount + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the ID of the offer that this discount is linked to + * + * @return int The ID + */ + public function getOfferId() { + return $this->offerId; + } + + /** + * Get the offer that this discount is linked to + * + * @return offer The offer + */ + public function getOffer() { + return new offer($this->pdo, $this->offerId); + } + + /** + * Get the title of the discount + * + * @return string The title + */ + public function getTitle() { + return $this->title; + } + + /** + * Set the title of the discount + * + * @param string $title The new title for the discount + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setTitle($title) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `title`=? WHERE `id`=?"); + $stmt->execute(array($title, $this->id)); + if ($stmt->rowCount() == 1) { + $this->title = $title; + return true; + } else { + return false; + } + } + + /** + * Get the description of the discount + * + * @param bool $parseMarkdown Whether or not to parse markdown + * + * @return string The description + */ + public function getDescription($parseMarkdown = true) { + if ($parseMarkdown) { + $pd = new Parsedown; + return $pd->text($this->description); + } else { + return $this->description; + } + } + + /** + * Set the description of the discount + * + * @param string $description The new description for the discount + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setDescription($description) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `description`=? WHERE `id`=?"); + $stmt->execute(array($description, $this->id)); + if ($stmt->rowCount() == 1) { + $this->description = $description; + return true; + } else { + return false; + } + } + + /** + * Get the value of the discount + * + * @return float The value + */ + public function getValue() { + return $this->value; + } + + /** + * Set the value of the discount + * + * @param float $value The new value for the discount + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setValue($value) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `value`=? WHERE `id`=?"); + $stmt->execute(array($value, $this->id)); + if ($stmt->rowCount() == 1) { + $this->value = $value; + return true; + } else { + return false; + } + } + + /** + * Get the VAT percentage of the discount + * + * @return float The VAT percentage + */ + public function getVAT() { + return $this->vat; + } + + /** + * Set the VAT percentage of the discount + * + * @param float $vat The new VAT percentage for the discount + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setVAT($vat) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `VAT_percentage`=? WHERE `id`=?"); + $stmt->execute(array($vat, $this->id)); + if ($stmt->rowCount() == 1) { + $this->vat = $vat; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Calculate useful numbers about the discount + * + * Subtotal: value + * + * VAT: subtotal \* VAT_percentage + * + * Total: subtotal + VAT + * + * @param int $what Any of discount::SUBTOTAL, discount::VAT, discount::TOTAL + * @param int $round How many decimals to round on + * @param bool $format Whether to format the number nicely (for output) or not (for calculations) + * + * @throws PDOException If something went wrong with the database + * + * @return float|bool The calculated value rounded on $round decimals, or false when the input is incorrect + */ + public function calculate($what = self::TOTAL, $round = 2, $format = true) { + $return = 0; + switch ($what) { + case self::SUBTOTAL: + $return = - $this->value; + break; + case self::VAT: + $return = $this->calculate(self::SUBTOTAL, $round + 1, false) * $this->getVAT() / 100; + break; + case self::TOTAL: + $return = $this->calculate(self::SUBTOTAL, $round + 1, false) + $this->calculate(self::VAT, $round + 1, false); + break; + default: + return false; + } + if ($format) { + return number_format($return, $round); + } else { + return round($return, $round); + } + } + + /** + * Remove this discount from the database + * + * If this doesn't succeed (i.e. false is returned), that means the discount was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."discount` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } +} diff --git a/classes/file.class.php b/classes/file.class.php deleted file mode 100644 index f6019ec..0000000 --- a/classes/file.class.php +++ /dev/null @@ -1,148 +0,0 @@ -. - */ - -/** - * An interface to the file table in the database - */ -class file { - /** - * @var PDO $pdo The PDO class for database communication - * @var int $id The id of the file - * @var string $filename The relative path to the file - */ - protected $pdo, $id, $filename; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the file to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the file could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."file` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The file with id '$id' could not be found."); - } - $file = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $file['id']; - $this->filename = $file['filename']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the file - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the relative filename of the file - * - * @see file::getFilenamePath To get the full internal path to the file - * @see file::getFilenameURI To get the full external path to the file - * - * @return string The filename - */ - public function getFilename() { - return $this->filename; - } - - /** - * Get the full internal path to the file - * - * @see file::getFilename To get the relative filename - * @see file::getFilenameURI To get the full external path to the file - * - * @return string The path - */ - public function getFilenamePath() { - return constants::files_folder . $this->filename; - } - - /** - * Get the full external path to the file - * - * @see file::getFilename To get the relative filename - * @see file::getFilenamePath To get the full internal path to the file - * - * @return string The URI - */ - public function getFilenameURI() { - return constants::files_folder_external . $this->filename; - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Move this file to the trash and delete all records for it - * - * Physically, this moves the file to a trash folder - * Then, the file will be removed from the file table in the database - * Any appendices linking to this file with fileId will have fileId NULL - * Any offers linking to this file with invoice_fileId will have invoice_fileId NULL - * - * @throws PDOException If there's something wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - // Try to move the file to trash - $newname = pathinfo($this->filename, PATHINFO_FILENAME) . '--' . date('Y-m-d.H.i.s.') . pathinfo($this->filename, PATHINFO_EXTENSION); - $newdir = pathinfo($this->getFilenamePath(), PATHINFO_DIRNAME) . '/' . constants::files_folder_trash . '/'; - if (!file_exists($newdir)) { - if (!mkdir($newdir)) { - return false; - } - } - if (!(@rename($this->getFilenamePath(), $newdir . $newname))) { - return false; - } - - // Remove offers linked by invoice_fileId - $this->pdo->query("UPDATE `".constants::db_prefix."offer` SET `invoice_fileId`=NULL WHERE `invoice_fileId`={$this->id}"); - - // Remove the record of the file - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."file` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() == 1) { - return true; - } else { - return false; - } - } -} \ No newline at end of file diff --git a/classes/file.php b/classes/file.php new file mode 100644 index 0000000..f6019ec --- /dev/null +++ b/classes/file.php @@ -0,0 +1,148 @@ +. + */ + +/** + * An interface to the file table in the database + */ +class file { + /** + * @var PDO $pdo The PDO class for database communication + * @var int $id The id of the file + * @var string $filename The relative path to the file + */ + protected $pdo, $id, $filename; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the file to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the file could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."file` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The file with id '$id' could not be found."); + } + $file = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $file['id']; + $this->filename = $file['filename']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the file + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the relative filename of the file + * + * @see file::getFilenamePath To get the full internal path to the file + * @see file::getFilenameURI To get the full external path to the file + * + * @return string The filename + */ + public function getFilename() { + return $this->filename; + } + + /** + * Get the full internal path to the file + * + * @see file::getFilename To get the relative filename + * @see file::getFilenameURI To get the full external path to the file + * + * @return string The path + */ + public function getFilenamePath() { + return constants::files_folder . $this->filename; + } + + /** + * Get the full external path to the file + * + * @see file::getFilename To get the relative filename + * @see file::getFilenamePath To get the full internal path to the file + * + * @return string The URI + */ + public function getFilenameURI() { + return constants::files_folder_external . $this->filename; + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Move this file to the trash and delete all records for it + * + * Physically, this moves the file to a trash folder + * Then, the file will be removed from the file table in the database + * Any appendices linking to this file with fileId will have fileId NULL + * Any offers linking to this file with invoice_fileId will have invoice_fileId NULL + * + * @throws PDOException If there's something wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + // Try to move the file to trash + $newname = pathinfo($this->filename, PATHINFO_FILENAME) . '--' . date('Y-m-d.H.i.s.') . pathinfo($this->filename, PATHINFO_EXTENSION); + $newdir = pathinfo($this->getFilenamePath(), PATHINFO_DIRNAME) . '/' . constants::files_folder_trash . '/'; + if (!file_exists($newdir)) { + if (!mkdir($newdir)) { + return false; + } + } + if (!(@rename($this->getFilenamePath(), $newdir . $newname))) { + return false; + } + + // Remove offers linked by invoice_fileId + $this->pdo->query("UPDATE `".constants::db_prefix."offer` SET `invoice_fileId`=NULL WHERE `invoice_fileId`={$this->id}"); + + // Remove the record of the file + $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."file` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() == 1) { + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/classes/fpdf.php b/classes/fpdf.php deleted file mode 100644 index 0dd1cb6..0000000 --- a/classes/fpdf.php +++ /dev/null @@ -1,1804 +0,0 @@ -_dochecks(); - // Initialization of properties - $this->page = 0; - $this->n = 2; - $this->buffer = ''; - $this->pages = array(); - $this->PageSizes = array(); - $this->state = 0; - $this->fonts = array(); - $this->FontFiles = array(); - $this->diffs = array(); - $this->images = array(); - $this->links = array(); - $this->InHeader = false; - $this->InFooter = false; - $this->lasth = 0; - $this->FontFamily = ''; - $this->FontStyle = ''; - $this->FontSizePt = 12; - $this->underline = false; - $this->DrawColor = '0 G'; - $this->FillColor = '0 g'; - $this->TextColor = '0 g'; - $this->ColorFlag = false; - $this->ws = 0; - // Font path - if(defined('FPDF_FONTPATH')) - { - $this->fontpath = FPDF_FONTPATH; - if(substr($this->fontpath,-1)!='/' && substr($this->fontpath,-1)!='\\') - $this->fontpath .= '/'; - } - elseif(is_dir(dirname(__FILE__).'/font')) - $this->fontpath = dirname(__FILE__).'/font/'; - else - $this->fontpath = ''; - // Core fonts - $this->CoreFonts = array('courier', 'helvetica', 'times', 'symbol', 'zapfdingbats'); - // Scale factor - if($unit=='pt') - $this->k = 1; - elseif($unit=='mm') - $this->k = 72/25.4; - elseif($unit=='cm') - $this->k = 72/2.54; - elseif($unit=='in') - $this->k = 72; - else - $this->Error('Incorrect unit: '.$unit); - // Page sizes - $this->StdPageSizes = array('a3'=>array(841.89,1190.55), 'a4'=>array(595.28,841.89), 'a5'=>array(420.94,595.28), - 'letter'=>array(612,792), 'legal'=>array(612,1008)); - $size = $this->_getpagesize($size); - $this->DefPageSize = $size; - $this->CurPageSize = $size; - // Page orientation - $orientation = strtolower($orientation); - if($orientation=='p' || $orientation=='portrait') - { - $this->DefOrientation = 'P'; - $this->w = $size[0]; - $this->h = $size[1]; - } - elseif($orientation=='l' || $orientation=='landscape') - { - $this->DefOrientation = 'L'; - $this->w = $size[1]; - $this->h = $size[0]; - } - else - $this->Error('Incorrect orientation: '.$orientation); - $this->CurOrientation = $this->DefOrientation; - $this->wPt = $this->w*$this->k; - $this->hPt = $this->h*$this->k; - // Page margins (1 cm) - $margin = 28.35/$this->k; - $this->SetMargins($margin,$margin); - // Interior cell margin (1 mm) - $this->cMargin = $margin/10; - // Line width (0.2 mm) - $this->LineWidth = .567/$this->k; - // Automatic page break - $this->SetAutoPageBreak(true,2*$margin); - // Default display mode - $this->SetDisplayMode('default'); - // Enable compression - $this->SetCompression(true); - // Set default PDF version number - $this->PDFVersion = '1.3'; -} - -function SetMargins($left, $top, $right=null) -{ - // Set left, top and right margins - $this->lMargin = $left; - $this->tMargin = $top; - if($right===null) - $right = $left; - $this->rMargin = $right; -} - -function SetLeftMargin($margin) -{ - // Set left margin - $this->lMargin = $margin; - if($this->page>0 && $this->x<$margin) - $this->x = $margin; -} - -function SetTopMargin($margin) -{ - // Set top margin - $this->tMargin = $margin; -} - -function SetRightMargin($margin) -{ - // Set right margin - $this->rMargin = $margin; -} - -function SetAutoPageBreak($auto, $margin=0) -{ - // Set auto page break mode and triggering margin - $this->AutoPageBreak = $auto; - $this->bMargin = $margin; - $this->PageBreakTrigger = $this->h-$margin; -} - -function SetDisplayMode($zoom, $layout='default') -{ - // Set display mode in viewer - if($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom)) - $this->ZoomMode = $zoom; - else - $this->Error('Incorrect zoom display mode: '.$zoom); - if($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default') - $this->LayoutMode = $layout; - else - $this->Error('Incorrect layout display mode: '.$layout); -} - -function SetCompression($compress) -{ - // Set page compression - if(function_exists('gzcompress')) - $this->compress = $compress; - else - $this->compress = false; -} - -function SetTitle($title, $isUTF8=false) -{ - // Title of document - if($isUTF8) - $title = $this->_UTF8toUTF16($title); - $this->title = $title; -} - -function SetSubject($subject, $isUTF8=false) -{ - // Subject of document - if($isUTF8) - $subject = $this->_UTF8toUTF16($subject); - $this->subject = $subject; -} - -function SetAuthor($author, $isUTF8=false) -{ - // Author of document - if($isUTF8) - $author = $this->_UTF8toUTF16($author); - $this->author = $author; -} - -function SetKeywords($keywords, $isUTF8=false) -{ - // Keywords of document - if($isUTF8) - $keywords = $this->_UTF8toUTF16($keywords); - $this->keywords = $keywords; -} - -function SetCreator($creator, $isUTF8=false) -{ - // Creator of document - if($isUTF8) - $creator = $this->_UTF8toUTF16($creator); - $this->creator = $creator; -} - -function AliasNbPages($alias='{nb}') -{ - // Define an alias for total number of pages - $this->AliasNbPages = $alias; -} - -function Error($msg) -{ - // Fatal error - die('FPDF error: '.$msg); -} - -function Open() -{ - // Begin document - $this->state = 1; -} - -function Close() -{ - // Terminate document - if($this->state==3) - return; - if($this->page==0) - $this->AddPage(); - // Page footer - $this->InFooter = true; - $this->Footer(); - $this->InFooter = false; - // Close page - $this->_endpage(); - // Close document - $this->_enddoc(); -} - -function AddPage($orientation='', $size='') -{ - // Start a new page - if($this->state==0) - $this->Open(); - $family = $this->FontFamily; - $style = $this->FontStyle.($this->underline ? 'U' : ''); - $fontsize = $this->FontSizePt; - $lw = $this->LineWidth; - $dc = $this->DrawColor; - $fc = $this->FillColor; - $tc = $this->TextColor; - $cf = $this->ColorFlag; - if($this->page>0) - { - // Page footer - $this->InFooter = true; - $this->Footer(); - $this->InFooter = false; - // Close page - $this->_endpage(); - } - // Start new page - $this->_beginpage($orientation,$size); - // Set line cap style to square - $this->_out('2 J'); - // Set line width - $this->LineWidth = $lw; - $this->_out(sprintf('%.2F w',$lw*$this->k)); - // Set font - if($family) - $this->SetFont($family,$style,$fontsize); - // Set colors - $this->DrawColor = $dc; - if($dc!='0 G') - $this->_out($dc); - $this->FillColor = $fc; - if($fc!='0 g') - $this->_out($fc); - $this->TextColor = $tc; - $this->ColorFlag = $cf; - // Page header - $this->InHeader = true; - $this->Header(); - $this->InHeader = false; - // Restore line width - if($this->LineWidth!=$lw) - { - $this->LineWidth = $lw; - $this->_out(sprintf('%.2F w',$lw*$this->k)); - } - // Restore font - if($family) - $this->SetFont($family,$style,$fontsize); - // Restore colors - if($this->DrawColor!=$dc) - { - $this->DrawColor = $dc; - $this->_out($dc); - } - if($this->FillColor!=$fc) - { - $this->FillColor = $fc; - $this->_out($fc); - } - $this->TextColor = $tc; - $this->ColorFlag = $cf; -} - -function Header() -{ - // To be implemented in your own inherited class -} - -function Footer() -{ - // To be implemented in your own inherited class -} - -function PageNo() -{ - // Get current page number - return $this->page; -} - -function SetDrawColor($r, $g=null, $b=null) -{ - // Set color for all stroking operations - if(($r==0 && $g==0 && $b==0) || $g===null) - $this->DrawColor = sprintf('%.3F G',$r/255); - else - $this->DrawColor = sprintf('%.3F %.3F %.3F RG',$r/255,$g/255,$b/255); - if($this->page>0) - $this->_out($this->DrawColor); -} - -function SetFillColor($r, $g=null, $b=null) -{ - // Set color for all filling operations - if(($r==0 && $g==0 && $b==0) || $g===null) - $this->FillColor = sprintf('%.3F g',$r/255); - else - $this->FillColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255); - $this->ColorFlag = ($this->FillColor!=$this->TextColor); - if($this->page>0) - $this->_out($this->FillColor); -} - -function SetTextColor($r, $g=null, $b=null) -{ - // Set color for text - if(($r==0 && $g==0 && $b==0) || $g===null) - $this->TextColor = sprintf('%.3F g',$r/255); - else - $this->TextColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255); - $this->ColorFlag = ($this->FillColor!=$this->TextColor); -} - -function GetStringWidth($s) -{ - // Get width of a string in the current font - $s = (string)$s; - $cw = &$this->CurrentFont['cw']; - $w = 0; - $l = strlen($s); - for($i=0;$i<$l;$i++) - $w += $cw[$s[$i]]; - return $w*$this->FontSize/1000; -} - -function SetLineWidth($width) -{ - // Set line width - $this->LineWidth = $width; - if($this->page>0) - $this->_out(sprintf('%.2F w',$width*$this->k)); -} - -function Line($x1, $y1, $x2, $y2) -{ - // Draw a line - $this->_out(sprintf('%.2F %.2F m %.2F %.2F l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k)); -} - -function Rect($x, $y, $w, $h, $style='') -{ - // Draw a rectangle - if($style=='F') - $op = 'f'; - elseif($style=='FD' || $style=='DF') - $op = 'B'; - else - $op = 'S'; - $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op)); -} - -function AddFont($family, $style='', $file='') -{ - // Add a TrueType, OpenType or Type1 font - $family = strtolower($family); - if($file=='') - $file = str_replace(' ','',$family).strtolower($style).'.php'; - $style = strtoupper($style); - if($style=='IB') - $style = 'BI'; - $fontkey = $family.$style; - if(isset($this->fonts[$fontkey])) - return; - $info = $this->_loadfont($file); - $info['i'] = count($this->fonts)+1; - if(!empty($info['diff'])) - { - // Search existing encodings - $n = array_search($info['diff'],$this->diffs); - if(!$n) - { - $n = count($this->diffs)+1; - $this->diffs[$n] = $info['diff']; - } - $info['diffn'] = $n; - } - if(!empty($info['file'])) - { - // Embedded font - if($info['type']=='TrueType') - $this->FontFiles[$info['file']] = array('length1'=>$info['originalsize']); - else - $this->FontFiles[$info['file']] = array('length1'=>$info['size1'], 'length2'=>$info['size2']); - } - $this->fonts[$fontkey] = $info; -} - -function SetFont($family, $style='', $size=0) -{ - // Select a font; size given in points - if($family=='') - $family = $this->FontFamily; - else - $family = strtolower($family); - $style = strtoupper($style); - if(strpos($style,'U')!==false) - { - $this->underline = true; - $style = str_replace('U','',$style); - } - else - $this->underline = false; - if($style=='IB') - $style = 'BI'; - if($size==0) - $size = $this->FontSizePt; - // Test if font is already selected - if($this->FontFamily==$family && $this->FontStyle==$style && $this->FontSizePt==$size) - return; - // Test if font is already loaded - $fontkey = $family.$style; - if(!isset($this->fonts[$fontkey])) - { - // Test if one of the core fonts - if($family=='arial') - $family = 'helvetica'; - if(in_array($family,$this->CoreFonts)) - { - if($family=='symbol' || $family=='zapfdingbats') - $style = ''; - $fontkey = $family.$style; - if(!isset($this->fonts[$fontkey])) - $this->AddFont($family,$style); - } - else - $this->Error('Undefined font: '.$family.' '.$style); - } - // Select it - $this->FontFamily = $family; - $this->FontStyle = $style; - $this->FontSizePt = $size; - $this->FontSize = $size/$this->k; - $this->CurrentFont = &$this->fonts[$fontkey]; - if($this->page>0) - $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); -} - -function SetFontSize($size) -{ - // Set font size in points - if($this->FontSizePt==$size) - return; - $this->FontSizePt = $size; - $this->FontSize = $size/$this->k; - if($this->page>0) - $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); -} - -function AddLink() -{ - // Create a new internal link - $n = count($this->links)+1; - $this->links[$n] = array(0, 0); - return $n; -} - -function SetLink($link, $y=0, $page=-1) -{ - // Set destination of internal link - if($y==-1) - $y = $this->y; - if($page==-1) - $page = $this->page; - $this->links[$link] = array($page, $y); -} - -function Link($x, $y, $w, $h, $link) -{ - // Put a link on the page - $this->PageLinks[$this->page][] = array($x*$this->k, $this->hPt-$y*$this->k, $w*$this->k, $h*$this->k, $link); -} - -function Text($x, $y, $txt) -{ - // Output a string - $s = sprintf('BT %.2F %.2F Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt)); - if($this->underline && $txt!='') - $s .= ' '.$this->_dounderline($x,$y,$txt); - if($this->ColorFlag) - $s = 'q '.$this->TextColor.' '.$s.' Q'; - $this->_out($s); -} - -function AcceptPageBreak() -{ - // Accept automatic page break or not - return $this->AutoPageBreak; -} - -function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='') -{ - // Output a cell - $k = $this->k; - if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) - { - // Automatic page break - $x = $this->x; - $ws = $this->ws; - if($ws>0) - { - $this->ws = 0; - $this->_out('0 Tw'); - } - $this->AddPage($this->CurOrientation,$this->CurPageSize); - $this->x = $x; - if($ws>0) - { - $this->ws = $ws; - $this->_out(sprintf('%.3F Tw',$ws*$k)); - } - } - if($w==0) - $w = $this->w-$this->rMargin-$this->x; - $s = ''; - if($fill || $border==1) - { - if($fill) - $op = ($border==1) ? 'B' : 'f'; - else - $op = 'S'; - $s = sprintf('%.2F %.2F %.2F %.2F re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op); - } - if(is_string($border)) - { - $x = $this->x; - $y = $this->y; - if(strpos($border,'L')!==false) - $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k); - if(strpos($border,'T')!==false) - $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k); - if(strpos($border,'R')!==false) - $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k); - if(strpos($border,'B')!==false) - $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k); - } - if($txt!=='') - { - if($align=='R') - $dx = $w-$this->cMargin-$this->GetStringWidth($txt); - elseif($align=='C') - $dx = ($w-$this->GetStringWidth($txt))/2; - else - $dx = $this->cMargin; - if($this->ColorFlag) - $s .= 'q '.$this->TextColor.' '; - $txt2 = str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt))); - $s .= sprintf('BT %.2F %.2F Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt2); - if($this->underline) - $s .= ' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt); - if($this->ColorFlag) - $s .= ' Q'; - if($link) - $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link); - } - if($s) - $this->_out($s); - $this->lasth = $h; - if($ln>0) - { - // Go to next line - $this->y += $h; - if($ln==1) - $this->x = $this->lMargin; - } - else - $this->x += $w; -} - -function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false) -{ - // Output text with automatic or explicit line breaks - $cw = &$this->CurrentFont['cw']; - if($w==0) - $w = $this->w-$this->rMargin-$this->x; - $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; - $s = str_replace("\r",'',$txt); - $nb = strlen($s); - if($nb>0 && $s[$nb-1]=="\n") - $nb--; - $b = 0; - if($border) - { - if($border==1) - { - $border = 'LTRB'; - $b = 'LRT'; - $b2 = 'LR'; - } - else - { - $b2 = ''; - if(strpos($border,'L')!==false) - $b2 .= 'L'; - if(strpos($border,'R')!==false) - $b2 .= 'R'; - $b = (strpos($border,'T')!==false) ? $b2.'T' : $b2; - } - } - $sep = -1; - $i = 0; - $j = 0; - $l = 0; - $ns = 0; - $nl = 1; - while($i<$nb) - { - // Get next character - $c = $s[$i]; - if($c=="\n") - { - // Explicit line break - if($this->ws>0) - { - $this->ws = 0; - $this->_out('0 Tw'); - } - $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); - $i++; - $sep = -1; - $j = $i; - $l = 0; - $ns = 0; - $nl++; - if($border && $nl==2) - $b = $b2; - continue; - } - if($c==' ') - { - $sep = $i; - $ls = $l; - $ns++; - } - $l += $cw[$c]; - if($l>$wmax) - { - // Automatic line break - if($sep==-1) - { - if($i==$j) - $i++; - if($this->ws>0) - { - $this->ws = 0; - $this->_out('0 Tw'); - } - $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); - } - else - { - if($align=='J') - { - $this->ws = ($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0; - $this->_out(sprintf('%.3F Tw',$this->ws*$this->k)); - } - $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill); - $i = $sep+1; - } - $sep = -1; - $j = $i; - $l = 0; - $ns = 0; - $nl++; - if($border && $nl==2) - $b = $b2; - } - else - $i++; - } - // Last chunk - if($this->ws>0) - { - $this->ws = 0; - $this->_out('0 Tw'); - } - if($border && strpos($border,'B')!==false) - $b .= 'B'; - $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); - $this->x = $this->lMargin; -} - -function Write($h, $txt, $link='') -{ - // Output text in flowing mode - $cw = &$this->CurrentFont['cw']; - $w = $this->w-$this->rMargin-$this->x; - $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; - $s = str_replace("\r",'',$txt); - $nb = strlen($s); - $sep = -1; - $i = 0; - $j = 0; - $l = 0; - $nl = 1; - while($i<$nb) - { - // Get next character - $c = $s[$i]; - if($c=="\n") - { - // Explicit line break - $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); - $i++; - $sep = -1; - $j = $i; - $l = 0; - if($nl==1) - { - $this->x = $this->lMargin; - $w = $this->w-$this->rMargin-$this->x; - $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; - } - $nl++; - continue; - } - if($c==' ') - $sep = $i; - $l += $cw[$c]; - if($l>$wmax) - { - // Automatic line break - if($sep==-1) - { - if($this->x>$this->lMargin) - { - // Move to next line - $this->x = $this->lMargin; - $this->y += $h; - $w = $this->w-$this->rMargin-$this->x; - $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; - $i++; - $nl++; - continue; - } - if($i==$j) - $i++; - $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); - } - else - { - $this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',0,$link); - $i = $sep+1; - } - $sep = -1; - $j = $i; - $l = 0; - if($nl==1) - { - $this->x = $this->lMargin; - $w = $this->w-$this->rMargin-$this->x; - $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; - } - $nl++; - } - else - $i++; - } - // Last chunk - if($i!=$j) - $this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',0,$link); -} - -function Ln($h=null) -{ - // Line feed; default value is last cell height - $this->x = $this->lMargin; - if($h===null) - $this->y += $this->lasth; - else - $this->y += $h; -} - -function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='') -{ - // Put an image on the page - if(!isset($this->images[$file])) - { - // First use of this image, get info - if($type=='') - { - $pos = strrpos($file,'.'); - if(!$pos) - $this->Error('Image file has no extension and no type was specified: '.$file); - $type = substr($file,$pos+1); - } - $type = strtolower($type); - if($type=='jpeg') - $type = 'jpg'; - $mtd = '_parse'.$type; - if(!method_exists($this,$mtd)) - $this->Error('Unsupported image type: '.$type); - $info = $this->$mtd($file); - $info['i'] = count($this->images)+1; - $this->images[$file] = $info; - } - else - $info = $this->images[$file]; - - // Automatic width and height calculation if needed - if($w==0 && $h==0) - { - // Put image at 96 dpi - $w = -96; - $h = -96; - } - if($w<0) - $w = -$info['w']*72/$w/$this->k; - if($h<0) - $h = -$info['h']*72/$h/$this->k; - if($w==0) - $w = $h*$info['w']/$info['h']; - if($h==0) - $h = $w*$info['h']/$info['w']; - - // Flowing mode - if($y===null) - { - if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) - { - // Automatic page break - $x2 = $this->x; - $this->AddPage($this->CurOrientation,$this->CurPageSize); - $this->x = $x2; - } - $y = $this->y; - $this->y += $h; - } - - if($x===null) - $x = $this->x; - $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i'])); - if($link) - $this->Link($x,$y,$w,$h,$link); -} - -function GetX() -{ - // Get x position - return $this->x; -} - -function SetX($x) -{ - // Set x position - if($x>=0) - $this->x = $x; - else - $this->x = $this->w+$x; -} - -function GetY() -{ - // Get y position - return $this->y; -} - -function SetY($y) -{ - // Set y position and reset x - $this->x = $this->lMargin; - if($y>=0) - $this->y = $y; - else - $this->y = $this->h+$y; -} - -function SetXY($x, $y) -{ - // Set x and y positions - $this->SetY($y); - $this->SetX($x); -} - -function Output($name='', $dest='') -{ - // Output PDF to some destination - if($this->state<3) - $this->Close(); - $dest = strtoupper($dest); - if($dest=='') - { - if($name=='') - { - $name = 'doc.pdf'; - $dest = 'I'; - } - else - $dest = 'F'; - } - switch($dest) - { - case 'I': - // Send to standard output - $this->_checkoutput(); - if(PHP_SAPI!='cli') - { - // We send to a browser - header('Content-Type: application/pdf'); - header('Content-Disposition: inline; filename="'.$name.'"'); - header('Cache-Control: private, max-age=0, must-revalidate'); - header('Pragma: public'); - } - echo $this->buffer; - break; - case 'D': - // Download file - $this->_checkoutput(); - header('Content-Type: application/x-download'); - header('Content-Disposition: attachment; filename="'.$name.'"'); - header('Cache-Control: private, max-age=0, must-revalidate'); - header('Pragma: public'); - echo $this->buffer; - break; - case 'F': - // Save to local file - $f = fopen($name,'wb'); - if(!$f) - $this->Error('Unable to create output file: '.$name); - fwrite($f,$this->buffer,strlen($this->buffer)); - fclose($f); - break; - case 'S': - // Return as a string - return $this->buffer; - default: - $this->Error('Incorrect output destination: '.$dest); - } - return ''; -} - -/******************************************************************************* -* * -* Protected methods * -* * -*******************************************************************************/ -function _dochecks() -{ - // Check availability of %F - if(sprintf('%.1F',1.0)!='1.0') - $this->Error('This version of PHP is not supported'); - // Check mbstring overloading - if(ini_get('mbstring.func_overload') & 2) - $this->Error('mbstring overloading must be disabled'); - // Ensure runtime magic quotes are disabled - if(get_magic_quotes_runtime()) - @set_magic_quotes_runtime(0); -} - -function _checkoutput() -{ - if(PHP_SAPI!='cli') - { - if(headers_sent($file,$line)) - $this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)"); - } - if(ob_get_length()) - { - // The output buffer is not empty - if(preg_match('/^(\xEF\xBB\xBF)?\s*$/',ob_get_contents())) - { - // It contains only a UTF-8 BOM and/or whitespace, let's clean it - ob_clean(); - } - else - $this->Error("Some data has already been output, can't send PDF file"); - } -} - -function _getpagesize($size) -{ - if(is_string($size)) - { - $size = strtolower($size); - if(!isset($this->StdPageSizes[$size])) - $this->Error('Unknown page size: '.$size); - $a = $this->StdPageSizes[$size]; - return array($a[0]/$this->k, $a[1]/$this->k); - } - else - { - if($size[0]>$size[1]) - return array($size[1], $size[0]); - else - return $size; - } -} - -function _beginpage($orientation, $size) -{ - $this->page++; - $this->pages[$this->page] = ''; - $this->state = 2; - $this->x = $this->lMargin; - $this->y = $this->tMargin; - $this->FontFamily = ''; - // Check page size and orientation - if($orientation=='') - $orientation = $this->DefOrientation; - else - $orientation = strtoupper($orientation[0]); - if($size=='') - $size = $this->DefPageSize; - else - $size = $this->_getpagesize($size); - if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1]) - { - // New size or orientation - if($orientation=='P') - { - $this->w = $size[0]; - $this->h = $size[1]; - } - else - { - $this->w = $size[1]; - $this->h = $size[0]; - } - $this->wPt = $this->w*$this->k; - $this->hPt = $this->h*$this->k; - $this->PageBreakTrigger = $this->h-$this->bMargin; - $this->CurOrientation = $orientation; - $this->CurPageSize = $size; - } - if($orientation!=$this->DefOrientation || $size[0]!=$this->DefPageSize[0] || $size[1]!=$this->DefPageSize[1]) - $this->PageSizes[$this->page] = array($this->wPt, $this->hPt); -} - -function _endpage() -{ - $this->state = 1; -} - -function _loadfont($font) -{ - // Load a font definition file from the font directory - include($this->fontpath.$font); - $a = get_defined_vars(); - if(!isset($a['name'])) - $this->Error('Could not include font definition file'); - return $a; -} - -function _escape($s) -{ - // Escape special characters in strings - $s = str_replace('\\','\\\\',$s); - $s = str_replace('(','\\(',$s); - $s = str_replace(')','\\)',$s); - $s = str_replace("\r",'\\r',$s); - return $s; -} - -function _textstring($s) -{ - // Format a text string - return '('.$this->_escape($s).')'; -} - -function _UTF8toUTF16($s) -{ - // Convert UTF-8 to UTF-16BE with BOM - $res = "\xFE\xFF"; - $nb = strlen($s); - $i = 0; - while($i<$nb) - { - $c1 = ord($s[$i++]); - if($c1>=224) - { - // 3-byte character - $c2 = ord($s[$i++]); - $c3 = ord($s[$i++]); - $res .= chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2)); - $res .= chr((($c2 & 0x03)<<6) + ($c3 & 0x3F)); - } - elseif($c1>=192) - { - // 2-byte character - $c2 = ord($s[$i++]); - $res .= chr(($c1 & 0x1C)>>2); - $res .= chr((($c1 & 0x03)<<6) + ($c2 & 0x3F)); - } - else - { - // Single-byte character - $res .= "\0".chr($c1); - } - } - return $res; -} - -function _dounderline($x, $y, $txt) -{ - // Underline text - $up = $this->CurrentFont['up']; - $ut = $this->CurrentFont['ut']; - $w = $this->GetStringWidth($txt)+$this->ws*substr_count($txt,' '); - return sprintf('%.2F %.2F %.2F %.2F re f',$x*$this->k,($this->h-($y-$up/1000*$this->FontSize))*$this->k,$w*$this->k,-$ut/1000*$this->FontSizePt); -} - -function _parsejpg($file) -{ - // Extract info from a JPEG file - $a = getimagesize($file); - if(!$a) - $this->Error('Missing or incorrect image file: '.$file); - if($a[2]!=2) - $this->Error('Not a JPEG file: '.$file); - if(!isset($a['channels']) || $a['channels']==3) - $colspace = 'DeviceRGB'; - elseif($a['channels']==4) - $colspace = 'DeviceCMYK'; - else - $colspace = 'DeviceGray'; - $bpc = isset($a['bits']) ? $a['bits'] : 8; - $data = file_get_contents($file); - return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data); -} - -function _parsepng($file) -{ - // Extract info from a PNG file - $f = fopen($file,'rb'); - if(!$f) - $this->Error('Can\'t open image file: '.$file); - $info = $this->_parsepngstream($f,$file); - fclose($f); - return $info; -} - -function _parsepngstream($f, $file) -{ - // Check signature - if($this->_readstream($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) - $this->Error('Not a PNG file: '.$file); - - // Read header chunk - $this->_readstream($f,4); - if($this->_readstream($f,4)!='IHDR') - $this->Error('Incorrect PNG file: '.$file); - $w = $this->_readint($f); - $h = $this->_readint($f); - $bpc = ord($this->_readstream($f,1)); - if($bpc>8) - $this->Error('16-bit depth not supported: '.$file); - $ct = ord($this->_readstream($f,1)); - if($ct==0 || $ct==4) - $colspace = 'DeviceGray'; - elseif($ct==2 || $ct==6) - $colspace = 'DeviceRGB'; - elseif($ct==3) - $colspace = 'Indexed'; - else - $this->Error('Unknown color type: '.$file); - if(ord($this->_readstream($f,1))!=0) - $this->Error('Unknown compression method: '.$file); - if(ord($this->_readstream($f,1))!=0) - $this->Error('Unknown filter method: '.$file); - if(ord($this->_readstream($f,1))!=0) - $this->Error('Interlacing not supported: '.$file); - $this->_readstream($f,4); - $dp = '/Predictor 15 /Colors '.($colspace=='DeviceRGB' ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w; - - // Scan chunks looking for palette, transparency and image data - $pal = ''; - $trns = ''; - $data = ''; - do - { - $n = $this->_readint($f); - $type = $this->_readstream($f,4); - if($type=='PLTE') - { - // Read palette - $pal = $this->_readstream($f,$n); - $this->_readstream($f,4); - } - elseif($type=='tRNS') - { - // Read transparency info - $t = $this->_readstream($f,$n); - if($ct==0) - $trns = array(ord(substr($t,1,1))); - elseif($ct==2) - $trns = array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1))); - else - { - $pos = strpos($t,chr(0)); - if($pos!==false) - $trns = array($pos); - } - $this->_readstream($f,4); - } - elseif($type=='IDAT') - { - // Read image data block - $data .= $this->_readstream($f,$n); - $this->_readstream($f,4); - } - elseif($type=='IEND') - break; - else - $this->_readstream($f,$n+4); - } - while($n); - - if($colspace=='Indexed' && empty($pal)) - $this->Error('Missing palette in '.$file); - $info = array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'dp'=>$dp, 'pal'=>$pal, 'trns'=>$trns); - if($ct>=4) - { - // Extract alpha channel - if(!function_exists('gzuncompress')) - $this->Error('Zlib not available, can\'t handle alpha channel: '.$file); - $data = gzuncompress($data); - $color = ''; - $alpha = ''; - if($ct==4) - { - // Gray image - $len = 2*$w; - for($i=0;$i<$h;$i++) - { - $pos = (1+$len)*$i; - $color .= $data[$pos]; - $alpha .= $data[$pos]; - $line = substr($data,$pos+1,$len); - $color .= preg_replace('/(.)./s','$1',$line); - $alpha .= preg_replace('/.(.)/s','$1',$line); - } - } - else - { - // RGB image - $len = 4*$w; - for($i=0;$i<$h;$i++) - { - $pos = (1+$len)*$i; - $color .= $data[$pos]; - $alpha .= $data[$pos]; - $line = substr($data,$pos+1,$len); - $color .= preg_replace('/(.{3})./s','$1',$line); - $alpha .= preg_replace('/.{3}(.)/s','$1',$line); - } - } - unset($data); - $data = gzcompress($color); - $info['smask'] = gzcompress($alpha); - if($this->PDFVersion<'1.4') - $this->PDFVersion = '1.4'; - } - $info['data'] = $data; - return $info; -} - -function _readstream($f, $n) -{ - // Read n bytes from stream - $res = ''; - while($n>0 && !feof($f)) - { - $s = fread($f,$n); - if($s===false) - $this->Error('Error while reading stream'); - $n -= strlen($s); - $res .= $s; - } - if($n>0) - $this->Error('Unexpected end of stream'); - return $res; -} - -function _readint($f) -{ - // Read a 4-byte integer from stream - $a = unpack('Ni',$this->_readstream($f,4)); - return $a['i']; -} - -function _parsegif($file) -{ - // Extract info from a GIF file (via PNG conversion) - if(!function_exists('imagepng')) - $this->Error('GD extension is required for GIF support'); - if(!function_exists('imagecreatefromgif')) - $this->Error('GD has no GIF read support'); - $im = imagecreatefromgif($file); - if(!$im) - $this->Error('Missing or incorrect image file: '.$file); - imageinterlace($im,0); - $f = @fopen('php://temp','rb+'); - if($f) - { - // Perform conversion in memory - ob_start(); - imagepng($im); - $data = ob_get_clean(); - imagedestroy($im); - fwrite($f,$data); - rewind($f); - $info = $this->_parsepngstream($f,$file); - fclose($f); - } - else - { - // Use temporary file - $tmp = tempnam('.','gif'); - if(!$tmp) - $this->Error('Unable to create a temporary file'); - if(!imagepng($im,$tmp)) - $this->Error('Error while saving to temporary file'); - imagedestroy($im); - $info = $this->_parsepng($tmp); - unlink($tmp); - } - return $info; -} - -function _newobj() -{ - // Begin a new object - $this->n++; - $this->offsets[$this->n] = strlen($this->buffer); - $this->_out($this->n.' 0 obj'); -} - -function _putstream($s) -{ - $this->_out('stream'); - $this->_out($s); - $this->_out('endstream'); -} - -function _out($s) -{ - // Add a line to the document - if($this->state==2) - $this->pages[$this->page] .= $s."\n"; - else - $this->buffer .= $s."\n"; -} - -function _putpages() -{ - $nb = $this->page; - if(!empty($this->AliasNbPages)) - { - // Replace number of pages - for($n=1;$n<=$nb;$n++) - $this->pages[$n] = str_replace($this->AliasNbPages,$nb,$this->pages[$n]); - } - if($this->DefOrientation=='P') - { - $wPt = $this->DefPageSize[0]*$this->k; - $hPt = $this->DefPageSize[1]*$this->k; - } - else - { - $wPt = $this->DefPageSize[1]*$this->k; - $hPt = $this->DefPageSize[0]*$this->k; - } - $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; - for($n=1;$n<=$nb;$n++) - { - // Page - $this->_newobj(); - $this->_out('<_out('/Parent 1 0 R'); - if(isset($this->PageSizes[$n])) - $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]',$this->PageSizes[$n][0],$this->PageSizes[$n][1])); - $this->_out('/Resources 2 0 R'); - if(isset($this->PageLinks[$n])) - { - // Links - $annots = '/Annots ['; - foreach($this->PageLinks[$n] as $pl) - { - $rect = sprintf('%.2F %.2F %.2F %.2F',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]); - $annots .= '<_textstring($pl[4]).'>>>>'; - else - { - $l = $this->links[$pl[4]]; - $h = isset($this->PageSizes[$l[0]]) ? $this->PageSizes[$l[0]][1] : $hPt; - $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>',1+2*$l[0],$h-$l[1]*$this->k); - } - } - $this->_out($annots.']'); - } - if($this->PDFVersion>'1.3') - $this->_out('/Group <>'); - $this->_out('/Contents '.($this->n+1).' 0 R>>'); - $this->_out('endobj'); - // Page content - $p = ($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n]; - $this->_newobj(); - $this->_out('<<'.$filter.'/Length '.strlen($p).'>>'); - $this->_putstream($p); - $this->_out('endobj'); - } - // Pages root - $this->offsets[1] = strlen($this->buffer); - $this->_out('1 0 obj'); - $this->_out('<_out($kids.']'); - $this->_out('/Count '.$nb); - $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]',$wPt,$hPt)); - $this->_out('>>'); - $this->_out('endobj'); -} - -function _putfonts() -{ - $nf = $this->n; - foreach($this->diffs as $diff) - { - // Encodings - $this->_newobj(); - $this->_out('<>'); - $this->_out('endobj'); - } - foreach($this->FontFiles as $file=>$info) - { - // Font file embedding - $this->_newobj(); - $this->FontFiles[$file]['n'] = $this->n; - $font = file_get_contents($this->fontpath.$file,true); - if(!$font) - $this->Error('Font file not found: '.$file); - $compressed = (substr($file,-2)=='.z'); - if(!$compressed && isset($info['length2'])) - $font = substr($font,6,$info['length1']).substr($font,6+$info['length1']+6,$info['length2']); - $this->_out('<_out('/Filter /FlateDecode'); - $this->_out('/Length1 '.$info['length1']); - if(isset($info['length2'])) - $this->_out('/Length2 '.$info['length2'].' /Length3 0'); - $this->_out('>>'); - $this->_putstream($font); - $this->_out('endobj'); - } - foreach($this->fonts as $k=>$font) - { - // Font objects - $this->fonts[$k]['n'] = $this->n+1; - $type = $font['type']; - $name = $font['name']; - if($type=='Core') - { - // Core font - $this->_newobj(); - $this->_out('<_out('/BaseFont /'.$name); - $this->_out('/Subtype /Type1'); - if($name!='Symbol' && $name!='ZapfDingbats') - $this->_out('/Encoding /WinAnsiEncoding'); - $this->_out('>>'); - $this->_out('endobj'); - } - elseif($type=='Type1' || $type=='TrueType') - { - // Additional Type1 or TrueType/OpenType font - $this->_newobj(); - $this->_out('<_out('/BaseFont /'.$name); - $this->_out('/Subtype /'.$type); - $this->_out('/FirstChar 32 /LastChar 255'); - $this->_out('/Widths '.($this->n+1).' 0 R'); - $this->_out('/FontDescriptor '.($this->n+2).' 0 R'); - if(isset($font['diffn'])) - $this->_out('/Encoding '.($nf+$font['diffn']).' 0 R'); - else - $this->_out('/Encoding /WinAnsiEncoding'); - $this->_out('>>'); - $this->_out('endobj'); - // Widths - $this->_newobj(); - $cw = &$font['cw']; - $s = '['; - for($i=32;$i<=255;$i++) - $s .= $cw[chr($i)].' '; - $this->_out($s.']'); - $this->_out('endobj'); - // Descriptor - $this->_newobj(); - $s = '<$v) - $s .= ' /'.$k.' '.$v; - if(!empty($font['file'])) - $s .= ' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R'; - $this->_out($s.'>>'); - $this->_out('endobj'); - } - else - { - // Allow for additional types - $mtd = '_put'.strtolower($type); - if(!method_exists($this,$mtd)) - $this->Error('Unsupported font type: '.$type); - $this->$mtd($font); - } - } -} - -function _putimages() -{ - foreach(array_keys($this->images) as $file) - { - $this->_putimage($this->images[$file]); - unset($this->images[$file]['data']); - unset($this->images[$file]['smask']); - } -} - -function _putimage(&$info) -{ - $this->_newobj(); - $info['n'] = $this->n; - $this->_out('<_out('/Subtype /Image'); - $this->_out('/Width '.$info['w']); - $this->_out('/Height '.$info['h']); - if($info['cs']=='Indexed') - $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]'); - else - { - $this->_out('/ColorSpace /'.$info['cs']); - if($info['cs']=='DeviceCMYK') - $this->_out('/Decode [1 0 1 0 1 0 1 0]'); - } - $this->_out('/BitsPerComponent '.$info['bpc']); - if(isset($info['f'])) - $this->_out('/Filter /'.$info['f']); - if(isset($info['dp'])) - $this->_out('/DecodeParms <<'.$info['dp'].'>>'); - if(isset($info['trns']) && is_array($info['trns'])) - { - $trns = ''; - for($i=0;$i_out('/Mask ['.$trns.']'); - } - if(isset($info['smask'])) - $this->_out('/SMask '.($this->n+1).' 0 R'); - $this->_out('/Length '.strlen($info['data']).'>>'); - $this->_putstream($info['data']); - $this->_out('endobj'); - // Soft mask - if(isset($info['smask'])) - { - $dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns '.$info['w']; - $smask = array('w'=>$info['w'], 'h'=>$info['h'], 'cs'=>'DeviceGray', 'bpc'=>8, 'f'=>$info['f'], 'dp'=>$dp, 'data'=>$info['smask']); - $this->_putimage($smask); - } - // Palette - if($info['cs']=='Indexed') - { - $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; - $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal']; - $this->_newobj(); - $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>'); - $this->_putstream($pal); - $this->_out('endobj'); - } -} - -function _putxobjectdict() -{ - foreach($this->images as $image) - $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); -} - -function _putresourcedict() -{ - $this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); - $this->_out('/Font <<'); - foreach($this->fonts as $font) - $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R'); - $this->_out('>>'); - $this->_out('/XObject <<'); - $this->_putxobjectdict(); - $this->_out('>>'); -} - -function _putresources() -{ - $this->_putfonts(); - $this->_putimages(); - // Resource dictionary - $this->offsets[2] = strlen($this->buffer); - $this->_out('2 0 obj'); - $this->_out('<<'); - $this->_putresourcedict(); - $this->_out('>>'); - $this->_out('endobj'); -} - -function _putinfo() -{ - $this->_out('/Producer '.$this->_textstring('FPDF '.FPDF_VERSION)); - if(!empty($this->title)) - $this->_out('/Title '.$this->_textstring($this->title)); - if(!empty($this->subject)) - $this->_out('/Subject '.$this->_textstring($this->subject)); - if(!empty($this->author)) - $this->_out('/Author '.$this->_textstring($this->author)); - if(!empty($this->keywords)) - $this->_out('/Keywords '.$this->_textstring($this->keywords)); - if(!empty($this->creator)) - $this->_out('/Creator '.$this->_textstring($this->creator)); - $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis'))); -} - -function _putcatalog() -{ - $this->_out('/Type /Catalog'); - $this->_out('/Pages 1 0 R'); - if($this->ZoomMode=='fullpage') - $this->_out('/OpenAction [3 0 R /Fit]'); - elseif($this->ZoomMode=='fullwidth') - $this->_out('/OpenAction [3 0 R /FitH null]'); - elseif($this->ZoomMode=='real') - $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); - elseif(!is_string($this->ZoomMode)) - $this->_out('/OpenAction [3 0 R /XYZ null null '.sprintf('%.2F',$this->ZoomMode/100).']'); - if($this->LayoutMode=='single') - $this->_out('/PageLayout /SinglePage'); - elseif($this->LayoutMode=='continuous') - $this->_out('/PageLayout /OneColumn'); - elseif($this->LayoutMode=='two') - $this->_out('/PageLayout /TwoColumnLeft'); -} - -function _putheader() -{ - $this->_out('%PDF-'.$this->PDFVersion); -} - -function _puttrailer() -{ - $this->_out('/Size '.($this->n+1)); - $this->_out('/Root '.$this->n.' 0 R'); - $this->_out('/Info '.($this->n-1).' 0 R'); -} - -function _enddoc() -{ - $this->_putheader(); - $this->_putpages(); - $this->_putresources(); - // Info - $this->_newobj(); - $this->_out('<<'); - $this->_putinfo(); - $this->_out('>>'); - $this->_out('endobj'); - // Catalog - $this->_newobj(); - $this->_out('<<'); - $this->_putcatalog(); - $this->_out('>>'); - $this->_out('endobj'); - // Cross-ref - $o = strlen($this->buffer); - $this->_out('xref'); - $this->_out('0 '.($this->n+1)); - $this->_out('0000000000 65535 f '); - for($i=1;$i<=$this->n;$i++) - $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i])); - // Trailer - $this->_out('trailer'); - $this->_out('<<'); - $this->_puttrailer(); - $this->_out('>>'); - $this->_out('startxref'); - $this->_out($o); - $this->_out('%%EOF'); - $this->state = 3; -} -// End of class -} - -// Handle special IE contype request -if(isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT']=='contype') -{ - header('Content-Type: application/pdf'); - exit; -} - -?> diff --git a/classes/offer.class.php b/classes/offer.class.php deleted file mode 100644 index 75cb4f6..0000000 --- a/classes/offer.class.php +++ /dev/null @@ -1,706 +0,0 @@ -. - */ - -/** - * An interface to the offer table in the database - */ -class offer { - /** - * @var pdo $pdo The PDO class for database communication - * @var int $id The id of the offer - * @var int $contactId The id of the contact this offer is linked to - * @var int $start_date A UNIX timestamp of the start date - * @var int $end_date A UNIX timestamp of the end date - * @var int $invoice_date A UNIX timestamp of the invoice date - * @var bool $accepted Whether the offer is accepted or not - * @var null|int $invoice_fileId If an invoice has been generated, an the id of the file - * @var null|int $payment_received A UNIX timestamp of the date the payment has been received - */ - protected $pdo, $id, $contactId, $start_date, $end_date, $invoice_date, $accepted, $invoice_fileId, $payment_received; - - const SUBTOTAL = 1; - const VAT = 2; - const TOTAL = 3; - - /** - * Create a new instance - * - * Blah - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the offer to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the offer could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."offer` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The offer with id '$id' could not be found."); - } - $offer = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $offer['id']; - $this->contactId = $offer['contactId']; - $this->start_date = strtotime($offer['start_date']); - $this->end_date = strtotime($offer['end_date']); - $this->invoice_date = strtotime($offer['invoice_date']); - $this->accepted = (bool) $offer['accepted']; - $this->invoice_fileId = $offer['invoice_fileId']; - $this->payment_received = ($offer['payment_received'] == null) ? null : strtotime($offer['payment_received']); - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the offer - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the ID of the contact that this offer is linked to - * - * @see offer::getContact() This function returns the contact as an instance of the object class - * - * @return int The ID - */ - public function getContactId() { - return $this->contactId; - } - - /** - * Get the contact that this offer is linked to - * - * @see offer::getContactId() This function returns just the id - * - * @return contact The contact - */ - public function getContact() { - return new contact($this->pdo, $this->contactId); - } - - /** - * Get all assignment ids for this offer - * - * @see offer::getAssignments() This funtion returns instances of the assignment class instead of just the ids - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public function getAssignmentIds() { - $ids = array(); - $assignments = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."assignment` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); - foreach ($assignments as $assignment) { - $ids[] = $assignment['id']; - } - return $ids; - } - - /** - * Get all assignments for this offer - * - * @see offer::getAssignmentIds() This function returns just the ids of the assignments, and not instances of the assignment class - * - * @throws PDOException If something went wrong with the database - * - * @return assignment[] An array indexed by id of instances of the assignment class - */ - public function getAssignments() { - $ids = $this->getAssignmentIds(); - $assignments = array(); - foreach ($ids as $id) { - $assignments[$id] = new assignment($this->pdo, $id); - } - return $assignments; - } - - /** - * Get all discount ids for this offer - * - * @see offer::getDiscounts() This funtion returns instances of the discount class instead of just the ids - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public function getDiscountIds() { - $ids = array(); - $discounts = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."discount` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); - foreach ($discounts as $discount) { - $ids[] = $discount['id']; - } - return $ids; - } - - /** - * Get all discounts for this offer - * - * @see offer::getDiscountIds() This function returns just the ids of the discounts, and not instances of the discount class - * - * @throws PDOException If something went wrong with the database - * - * @return discount[] An array indexed by id of instances of the discount class - */ - public function getDiscounts() { - $ids = $this->getDiscountIds(); - $discounts = array(); - foreach ($ids as $id) { - $discounts[$id] = new discount($this->pdo, $id); - } - return $discounts; - } - - /** - * Get the start date of the assignment - * - * @return int The start date as a UNIX timestamp - */ - public function getStartDate() { - return $this->start_date; - } - - /** - * Set the start date of the assignment - * - * @param int $start_date The new start date for the assignment as a UNIX timestamp - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setStartDate($start_date) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `start_date`=? WHERE `id`=?"); - $stmt->execute(array(date('Y-m-d', $start_date), $this->id)); - if ($stmt->rowCount() == 1) { - $this->start_date = $start_date; - return true; - } else { - return false; - } - } - - /** - * Get the end date of the assignment - * - * @return int The end date as a UNIX timestamp - */ - public function getEndDate() { - return $this->end_date; - } - - /** - * Set the end date of the assignment - * - * @param int $end_date The new end date for the assignment as a UNIX timestamp - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setEndDate($end_date) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `end_date`=? WHERE `id`=?"); - $stmt->execute(array(date('Y-m-d', $end_date), $this->id)); - if ($stmt->rowCount() == 1) { - $this->end_date = $end_date; - return true; - } else { - return false; - } - } - - /** - * Get the invoice date of the assignment - * - * @return int The invoice date as a UNIX timestamp - */ - public function getInvoiceDate() { - return $this->invoice_date; - } - - /** - * Set the invoice date of the assignment - * - * @param int $invoice_date The new invoice date for the assignment as a UNIX timestamp - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setInvoiceDate($invoice_date) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `invoice_date`=? WHERE `id`=?"); - $stmt->execute(array(date('Y-m-d', $invoice_date), $this->id)); - if ($stmt->rowCount() == 1) { - $this->invoice_date = $invoice_date; - return true; - } else { - return false; - } - } - - /** - * Get the date the payment was received - * - * @return int|null The date as a UNIX timestamp, or null if it wasn't received yet - */ - public function getPaymentReceived() { - return $this->payment_received; - } - - /** - * Set the payment received date of the assignment - * - * @param int $payment_received The new date the payment has been received as a UNIX timestamp - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setPaymentReceived($payment_received) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `payment_received`=? WHERE `id`=?"); - $stmt->execute(array(date('Y-m-d', $payment_received), $this->id)); - if ($stmt->rowCount() == 1) { - $this->payment_received = $payment_received; - return true; - } else { - return false; - } - } - - /** - * Check if the offer is accepted or not - * - * @return bool True if the offer is accepted, false if not - */ - public function isAccepted() { - return $this->accepted; - } - - /** - * Toggle the `accepted' status of the offer - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function toggleAccepted() { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `accepted`=? WHERE `id`=?"); - $new_value = !$this->accepted; - $stmt->execute(array($new_value, $this->id)); - if ($stmt->rowCount() == 1) { - $this->accepted = $new_value; - return true; - } else { - return false; - } - } - - /** - * Get the ID of the file that the invoice of this offer is linked to - * - * @see offer::getInvoiceFile() This function returns the file as an instance of the file class - * - * @return int The ID - */ - public function getInvoiceFileId() { - return $this->invoice_fileId; - } - - /** - * Get the file that the invoice this offer is linked to - * - * @see offer::getInvoiceId() This function returns just the id - * - * @return file|null The file, or null if it doesn't exist - */ - public function getInvoiceFile() { - if ($this->invoice_fileId != null) { - return new file($this->pdo, $this->invoice_fileId); - } else { - return null; - } - } - - /** - * Set the invoice file id of the assignment - * - * @param int $invoice_fileId The new invoice file id for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setInvoiceFileId($invoice_fileId) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `invoice_fileId`=? WHERE `id`=?"); - $stmt->execute(array($invoice_fileId, $this->id)); - if ($stmt->rowCount() == 1) { - $this->invoice_fileId = $invoice_fileId; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Calculate a handy number about the invoice - * - * Subtotal: the sum of the prices of the assignments excl. VAT - * - * VAT: the sum of all the VAT from all the assignments - * - * Total: the sum of subtotal and total - * - * @param int $what Any of offer::SUBTOTAL, offer::VAT and offer::TOTAL - * @param int $round How many decimals to round the result on - * @param bool $format Whether to format the number nicely (for output) or not (for calculations) - * - * @throws PDOException If something went wrong with the database - * - * @return float|bool The calculated value rounded to $round decimals, or false on incorrect input - */ - public function calculate($what = self::TOTAL, $round = 2, $format = true) { - $return = 0; - switch ($what) { - case self::SUBTOTAL: - foreach ($this->getAssignments() as $assignment) { - $return += $assignment->calculate(assignment::SUBTOTAL, $round + 1, false); - } - foreach ($this->getDiscounts() as $discount) { - $return += $discount->calculate(discount::SUBTOTAL, $round + 1, false); - } - break; - case self::VAT: - $assignments = $this->getAssignments(); - foreach ($assignments as $assignment) { - $return += $assignment->calculate(assignment::VAT, $round + 1, false); - } - foreach ($this->getDiscounts() as $discount) { - $return += $discount->calculate(discount::VAT, $round + 1, false); - } - break; - case self::TOTAL: - $return = $this->calculate(self::SUBTOTAL, $round + 1, false) + $this->calculate(self::VAT, $round + 1, false); - break; - default: - return false; - } - if ($format) { - return number_format($return, 2); - } else { - return round($return, 2); - } - } - - /** - * Remove this offer from the database - * - * If this doesn't succeed (i.e. false is returned), that means the offer was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."offer` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } - - /** - * Make a new assignment linked to this order - * - * @param string $title The title for this assignment - * @param string $description The description for this assignment - * @param int $hours The amount of hours to work on this assignment - * @param float $price_per_hour The price per hour on this assignment - * @param float $vat The VAT percentage (so, 21 for 21%, not 0.21!) - * - * @throws PDOException If something went wrong with the database - * @throws Exception If there was a problem with the input - * - * @return assignment A new instance of the assignment class containing the new assignment - */ - public function createAssignment($title, $description, $hours, $price_per_hour, $vat) { - $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."assignment` (`offerId`,`title`,`description`,`hours`,`price_per_hour`,`VAT_percentage`) VALUES (?,?,?,?,?,?)"); - $stmt->execute(array( - $this->id, - $title, - $description, - $hours, - $price_per_hour, - $vat - )); - if ($stmt->rowCount() == 1) { - return new assignment($this->pdo, $this->pdo->lastInsertId()); - } else { - $error = $stmt->errorInfo(); - throw new Exception($error[2]); - } - } - - /** - * Make a new discount linked to this order - * - * @param string $title The title for this discount - * @param string $description The description for this discount - * @param float $value The value for this discount - * @param float $vat The VAT percentage (so, 21 for 21%, not 0.21!) - * - * @throws PDOException If something went wrong with the database - * @throws Exception If there was a problem with the input - * - * @return discount A new instance of the discount class containing the new discount - */ - public function createDiscount($title, $description, $value, $vat) { - $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."discount` (`offerId`,`title`,`description`,`value`,`VAT_percentage`) VALUES (?,?,?,?,?)"); - $stmt->execute(array( - $this->id, - $title, - $description, - $value, - $vat - )); - if ($stmt->rowCount() == 1) { - return new discount($this->pdo, $this->pdo->lastInsertId()); - } else { - $error = $stmt->errorInfo(); - throw new Exception($error[2]); - } - } - - /** - * Generate a PDF invoice - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the file could not be written or an other error occured - * - * @return file An instance of the file class with information on the invoice file generated - */ - public function generateInvoice() { - // Check if we already have a file - $file = $this->getInvoiceFile(); - if (!($file instanceof file)) { - // If not, create a new file - $i = 1; - do { - $invoice_nr = date('Y',$this->invoice_date) . str_pad($i++, 2, '0', STR_PAD_LEFT); - $filename = 'invoice-' . $invoice_nr . '.pdf'; - } while (file_exists(constants::files_folder . $filename)); - $file = BusinessAdmin::createFile($this->pdo, $filename); - - $this->setInvoiceFileId($file->getId()); - } else { - $invoice_nr = str_replace(array('invoice-','.pdf'), array('',''), $file->getFilename()); - } - - $list = array(); - foreach ($this->getAssignments() as $assignment) - $list[] = array( - $assignment->getTitle(), - $assignment->getPricePerHour() * $assignment->getHours(), - $assignment->getVAT() . "%", - $assignment->getPricePerHour() * $assignment->getHours() * (1 + $assignment->getVAT() / 100) - ); - foreach ($this->getDiscounts() as $discount) - $list[] = array( - $discount->getTitle(), - $discount->calculate(discount::SUBTOTAL), - $discount->getVAT() . "%", - $discount->calculate(discount::TOTAL) - ); - - $pdf = new correspondence(); - $pdf->SetContact($this->getContact()); - $pdf->SetTitle($pdf->_('invoice') . ' ' . $invoice_nr); - $pdf->AddPage(); - $pdf->correspondenceHeader(); - - $pdf->SetY(100); - $pdf->SetFont('','B',14); - $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); - $pdf->Cell(60,6, $pdf->_('invoice'),'B'); - $pdf->SetTextColor(0); - $pdf->Ln(); - - $width = array(90,25,20,25); - $subtotal = 0; - $btw = array(); - $total = 0; - - // Header - - $pdf->SetFont('','',9); - $pdf->Cell(60,4); - $pdf->Ln(); - $pdf->SetFont('','B'); - $pdf->Cell(30,4.5,$pdf->_('invoice-date')); - $pdf->SetFont('',''); - $pdf->Cell(50,4.5,date("d-m-Y", $this->invoice_date)); - $pdf->Ln(); - $pdf->SetFont('','B'); - $pdf->Cell(30,4.5,$pdf->_('invoice-nr')); - $pdf->SetFont('',''); - $pdf->Cell(50,4.5,$invoice_nr); - $pdf->Ln(); - $pdf->SetFont('','B'); - $pdf->Cell(30,4.5,$pdf->_('due-date')); - $pdf->SetFont('',''); - $pdf->Cell(50,4.5,date("d-m-Y",$this->invoice_date+3600*24*30)); - $pdf->Ln(); - $pdf->Cell(60,4.5,'','B'); - $pdf->Ln(); - - $pdf->SetY(140); - - // Table - - $pdf->SetFont('','B',11); - $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); - $pdf->Cell($width[0],7,$pdf->_('description'),'B'); - $pdf->Cell($width[1],7,$pdf->_('price-excl'),'B',0,'R'); - $pdf->Cell($width[2],7,$pdf->_('vat'),'B',0,'R'); - $pdf->Cell($width[3],7,$pdf->_('price-incl'),'B',0,'R'); - $pdf->SetTextColor(0); - $pdf->Ln(); - - $pdf->SetFont('',''); - foreach ($list as $row) { - $x = $pdf->getX(); - $y = $pdf->getY(); - $pdf->MultiCell($width[0],6,iconv('utf-8', 'iso-8859-1', $row[0]),0,'L'); - $newy = $pdf->getY(); - $pdf->SetXY($x + $width[0], $y); - $pdf->Cell($width[1],6,correspondence::valuta().number_format($row[1],2),'',0,'R'); - $pdf->Cell($width[2],6,round($row[2],0) . '%','',0,'R'); - $pdf->Cell($width[3],6,correspondence::valuta().number_format($row[3],2),'',0,'R'); - $pdf->Ln(); - $pdf->SetY($newy); - $pdf->addPageIfOnEnd(); - $subtotal += $row[1]; - if (!isset($btw[$row[2]])) $btw[$row[2]] = 0; - $btw[$row[2]] += $row[3] - $row[1]; - } - $total = $subtotal; - foreach ($btw as $m) { - $total += $m; - } - - $pdf->Cell(array_sum($width),5,'','T'); - $pdf->Ln(); - $pdf->Cell(array_sum($width),5); - $pdf->Ln(); - - $pdf->Cell($width[0],7); - $pdf->SetFont('','B'); - $pdf->Cell($width[1] + $width[2],7,$pdf->_('amount')); - $pdf->SetFont('',''); - $pdf->Cell($width[3],7,correspondence::valuta() . $this->calculate(self::SUBTOTAL),'',0,'R'); - $pdf->Ln(); - - foreach ($btw as $p => $m) { - $pdf->Cell($width[0],7); - $pdf->Cell($width[1] + $width[2],7,$pdf->_('vat') . ' '.round($p,0).'%'); - $pdf->Cell($width[3],7,correspondence::valuta() . number_format($m,2),'',0,'R'); - $pdf->Ln(); - } - - $pdf->Cell(array_sum($width),5); - $pdf->Ln(); - - $pdf->Cell($width[0],7); - $pdf->SetFont('','B'); - $pdf->Cell($width[1] + $width[2],7,$pdf->_('total')); - $pdf->SetFont('',''); - $pdf->Cell($width[3],7,correspondence::valuta() . $this->calculate(self::TOTAL),'T',0,'R'); - $pdf->Ln(); - - // Footer - - $pdf->Ln(); - $pdf->addPageIfOnEnd(); - if ($pdf->GetY() < 230) { - $pdf->SetY(230); - } - $oldY = $pdf->GetY(); - $pdf->Cell(45,20,'',1); - $pdf->Cell(12.5,20); - $pdf->Cell(45,20,'',1); - $pdf->Cell(12.5,20); - $pdf->Cell(45,20,'',1); - - $pdf->SetFont('','B',10); - $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); - $pdf->SetY($oldY + 3); - $pdf->Cell(5,5); - $pdf->Cell(40,5,$pdf->_('iban')); - $pdf->Cell(17.5,5); - $pdf->Cell(40,5,$pdf->_('invoice-nr')); - $pdf->Cell(17.5,5); - $pdf->Cell(40,5,$pdf->_('amount-due')); - $pdf->SetTextColor(0); - - $pdf->SetFont('','',8); - $pdf->Ln(); - $pdf->Ln(); - $oldY = $pdf->GetY(); - - $pdf->Cell(5,5); - $pdf->Cell(40,5, constants::invoice_iban); - $pdf->Cell(17.5,5); - $pdf->Cell(40,5,$invoice_nr); - $pdf->Cell(17.5,5); - $pdf->Cell(40,5,correspondence::valuta() . $this->calculate(self::TOTAL)); - - $pdf->SetY($oldY + 14); - - $pdf->SetFontSize(7); - $pdf->Cell(160,5,$pdf->_('request'),0,0,'C'); - $pdf->Ln(); - $pdf->Cell(160,5,str_replace('%%', constants::invoice_bic, $pdf->_('biccode')),0,0,'C'); - - if (file_exists($file->getFilenamePath())) { - unlink($file->getFilenamePath()); - } - $pdf->Output($file->getFilenamePath(),'F'); - chmod($file->getFilenamePath(),0644); - - return $file; - } -} diff --git a/classes/offer.php b/classes/offer.php new file mode 100644 index 0000000..75cb4f6 --- /dev/null +++ b/classes/offer.php @@ -0,0 +1,706 @@ +. + */ + +/** + * An interface to the offer table in the database + */ +class offer { + /** + * @var pdo $pdo The PDO class for database communication + * @var int $id The id of the offer + * @var int $contactId The id of the contact this offer is linked to + * @var int $start_date A UNIX timestamp of the start date + * @var int $end_date A UNIX timestamp of the end date + * @var int $invoice_date A UNIX timestamp of the invoice date + * @var bool $accepted Whether the offer is accepted or not + * @var null|int $invoice_fileId If an invoice has been generated, an the id of the file + * @var null|int $payment_received A UNIX timestamp of the date the payment has been received + */ + protected $pdo, $id, $contactId, $start_date, $end_date, $invoice_date, $accepted, $invoice_fileId, $payment_received; + + const SUBTOTAL = 1; + const VAT = 2; + const TOTAL = 3; + + /** + * Create a new instance + * + * Blah + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the offer to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the offer could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."offer` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The offer with id '$id' could not be found."); + } + $offer = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $offer['id']; + $this->contactId = $offer['contactId']; + $this->start_date = strtotime($offer['start_date']); + $this->end_date = strtotime($offer['end_date']); + $this->invoice_date = strtotime($offer['invoice_date']); + $this->accepted = (bool) $offer['accepted']; + $this->invoice_fileId = $offer['invoice_fileId']; + $this->payment_received = ($offer['payment_received'] == null) ? null : strtotime($offer['payment_received']); + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the offer + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the ID of the contact that this offer is linked to + * + * @see offer::getContact() This function returns the contact as an instance of the object class + * + * @return int The ID + */ + public function getContactId() { + return $this->contactId; + } + + /** + * Get the contact that this offer is linked to + * + * @see offer::getContactId() This function returns just the id + * + * @return contact The contact + */ + public function getContact() { + return new contact($this->pdo, $this->contactId); + } + + /** + * Get all assignment ids for this offer + * + * @see offer::getAssignments() This funtion returns instances of the assignment class instead of just the ids + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public function getAssignmentIds() { + $ids = array(); + $assignments = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."assignment` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); + foreach ($assignments as $assignment) { + $ids[] = $assignment['id']; + } + return $ids; + } + + /** + * Get all assignments for this offer + * + * @see offer::getAssignmentIds() This function returns just the ids of the assignments, and not instances of the assignment class + * + * @throws PDOException If something went wrong with the database + * + * @return assignment[] An array indexed by id of instances of the assignment class + */ + public function getAssignments() { + $ids = $this->getAssignmentIds(); + $assignments = array(); + foreach ($ids as $id) { + $assignments[$id] = new assignment($this->pdo, $id); + } + return $assignments; + } + + /** + * Get all discount ids for this offer + * + * @see offer::getDiscounts() This funtion returns instances of the discount class instead of just the ids + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public function getDiscountIds() { + $ids = array(); + $discounts = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."discount` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); + foreach ($discounts as $discount) { + $ids[] = $discount['id']; + } + return $ids; + } + + /** + * Get all discounts for this offer + * + * @see offer::getDiscountIds() This function returns just the ids of the discounts, and not instances of the discount class + * + * @throws PDOException If something went wrong with the database + * + * @return discount[] An array indexed by id of instances of the discount class + */ + public function getDiscounts() { + $ids = $this->getDiscountIds(); + $discounts = array(); + foreach ($ids as $id) { + $discounts[$id] = new discount($this->pdo, $id); + } + return $discounts; + } + + /** + * Get the start date of the assignment + * + * @return int The start date as a UNIX timestamp + */ + public function getStartDate() { + return $this->start_date; + } + + /** + * Set the start date of the assignment + * + * @param int $start_date The new start date for the assignment as a UNIX timestamp + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setStartDate($start_date) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `start_date`=? WHERE `id`=?"); + $stmt->execute(array(date('Y-m-d', $start_date), $this->id)); + if ($stmt->rowCount() == 1) { + $this->start_date = $start_date; + return true; + } else { + return false; + } + } + + /** + * Get the end date of the assignment + * + * @return int The end date as a UNIX timestamp + */ + public function getEndDate() { + return $this->end_date; + } + + /** + * Set the end date of the assignment + * + * @param int $end_date The new end date for the assignment as a UNIX timestamp + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setEndDate($end_date) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `end_date`=? WHERE `id`=?"); + $stmt->execute(array(date('Y-m-d', $end_date), $this->id)); + if ($stmt->rowCount() == 1) { + $this->end_date = $end_date; + return true; + } else { + return false; + } + } + + /** + * Get the invoice date of the assignment + * + * @return int The invoice date as a UNIX timestamp + */ + public function getInvoiceDate() { + return $this->invoice_date; + } + + /** + * Set the invoice date of the assignment + * + * @param int $invoice_date The new invoice date for the assignment as a UNIX timestamp + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setInvoiceDate($invoice_date) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `invoice_date`=? WHERE `id`=?"); + $stmt->execute(array(date('Y-m-d', $invoice_date), $this->id)); + if ($stmt->rowCount() == 1) { + $this->invoice_date = $invoice_date; + return true; + } else { + return false; + } + } + + /** + * Get the date the payment was received + * + * @return int|null The date as a UNIX timestamp, or null if it wasn't received yet + */ + public function getPaymentReceived() { + return $this->payment_received; + } + + /** + * Set the payment received date of the assignment + * + * @param int $payment_received The new date the payment has been received as a UNIX timestamp + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setPaymentReceived($payment_received) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `payment_received`=? WHERE `id`=?"); + $stmt->execute(array(date('Y-m-d', $payment_received), $this->id)); + if ($stmt->rowCount() == 1) { + $this->payment_received = $payment_received; + return true; + } else { + return false; + } + } + + /** + * Check if the offer is accepted or not + * + * @return bool True if the offer is accepted, false if not + */ + public function isAccepted() { + return $this->accepted; + } + + /** + * Toggle the `accepted' status of the offer + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function toggleAccepted() { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `accepted`=? WHERE `id`=?"); + $new_value = !$this->accepted; + $stmt->execute(array($new_value, $this->id)); + if ($stmt->rowCount() == 1) { + $this->accepted = $new_value; + return true; + } else { + return false; + } + } + + /** + * Get the ID of the file that the invoice of this offer is linked to + * + * @see offer::getInvoiceFile() This function returns the file as an instance of the file class + * + * @return int The ID + */ + public function getInvoiceFileId() { + return $this->invoice_fileId; + } + + /** + * Get the file that the invoice this offer is linked to + * + * @see offer::getInvoiceId() This function returns just the id + * + * @return file|null The file, or null if it doesn't exist + */ + public function getInvoiceFile() { + if ($this->invoice_fileId != null) { + return new file($this->pdo, $this->invoice_fileId); + } else { + return null; + } + } + + /** + * Set the invoice file id of the assignment + * + * @param int $invoice_fileId The new invoice file id for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setInvoiceFileId($invoice_fileId) { + $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `invoice_fileId`=? WHERE `id`=?"); + $stmt->execute(array($invoice_fileId, $this->id)); + if ($stmt->rowCount() == 1) { + $this->invoice_fileId = $invoice_fileId; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Calculate a handy number about the invoice + * + * Subtotal: the sum of the prices of the assignments excl. VAT + * + * VAT: the sum of all the VAT from all the assignments + * + * Total: the sum of subtotal and total + * + * @param int $what Any of offer::SUBTOTAL, offer::VAT and offer::TOTAL + * @param int $round How many decimals to round the result on + * @param bool $format Whether to format the number nicely (for output) or not (for calculations) + * + * @throws PDOException If something went wrong with the database + * + * @return float|bool The calculated value rounded to $round decimals, or false on incorrect input + */ + public function calculate($what = self::TOTAL, $round = 2, $format = true) { + $return = 0; + switch ($what) { + case self::SUBTOTAL: + foreach ($this->getAssignments() as $assignment) { + $return += $assignment->calculate(assignment::SUBTOTAL, $round + 1, false); + } + foreach ($this->getDiscounts() as $discount) { + $return += $discount->calculate(discount::SUBTOTAL, $round + 1, false); + } + break; + case self::VAT: + $assignments = $this->getAssignments(); + foreach ($assignments as $assignment) { + $return += $assignment->calculate(assignment::VAT, $round + 1, false); + } + foreach ($this->getDiscounts() as $discount) { + $return += $discount->calculate(discount::VAT, $round + 1, false); + } + break; + case self::TOTAL: + $return = $this->calculate(self::SUBTOTAL, $round + 1, false) + $this->calculate(self::VAT, $round + 1, false); + break; + default: + return false; + } + if ($format) { + return number_format($return, 2); + } else { + return round($return, 2); + } + } + + /** + * Remove this offer from the database + * + * If this doesn't succeed (i.e. false is returned), that means the offer was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."offer` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } + + /** + * Make a new assignment linked to this order + * + * @param string $title The title for this assignment + * @param string $description The description for this assignment + * @param int $hours The amount of hours to work on this assignment + * @param float $price_per_hour The price per hour on this assignment + * @param float $vat The VAT percentage (so, 21 for 21%, not 0.21!) + * + * @throws PDOException If something went wrong with the database + * @throws Exception If there was a problem with the input + * + * @return assignment A new instance of the assignment class containing the new assignment + */ + public function createAssignment($title, $description, $hours, $price_per_hour, $vat) { + $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."assignment` (`offerId`,`title`,`description`,`hours`,`price_per_hour`,`VAT_percentage`) VALUES (?,?,?,?,?,?)"); + $stmt->execute(array( + $this->id, + $title, + $description, + $hours, + $price_per_hour, + $vat + )); + if ($stmt->rowCount() == 1) { + return new assignment($this->pdo, $this->pdo->lastInsertId()); + } else { + $error = $stmt->errorInfo(); + throw new Exception($error[2]); + } + } + + /** + * Make a new discount linked to this order + * + * @param string $title The title for this discount + * @param string $description The description for this discount + * @param float $value The value for this discount + * @param float $vat The VAT percentage (so, 21 for 21%, not 0.21!) + * + * @throws PDOException If something went wrong with the database + * @throws Exception If there was a problem with the input + * + * @return discount A new instance of the discount class containing the new discount + */ + public function createDiscount($title, $description, $value, $vat) { + $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."discount` (`offerId`,`title`,`description`,`value`,`VAT_percentage`) VALUES (?,?,?,?,?)"); + $stmt->execute(array( + $this->id, + $title, + $description, + $value, + $vat + )); + if ($stmt->rowCount() == 1) { + return new discount($this->pdo, $this->pdo->lastInsertId()); + } else { + $error = $stmt->errorInfo(); + throw new Exception($error[2]); + } + } + + /** + * Generate a PDF invoice + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the file could not be written or an other error occured + * + * @return file An instance of the file class with information on the invoice file generated + */ + public function generateInvoice() { + // Check if we already have a file + $file = $this->getInvoiceFile(); + if (!($file instanceof file)) { + // If not, create a new file + $i = 1; + do { + $invoice_nr = date('Y',$this->invoice_date) . str_pad($i++, 2, '0', STR_PAD_LEFT); + $filename = 'invoice-' . $invoice_nr . '.pdf'; + } while (file_exists(constants::files_folder . $filename)); + $file = BusinessAdmin::createFile($this->pdo, $filename); + + $this->setInvoiceFileId($file->getId()); + } else { + $invoice_nr = str_replace(array('invoice-','.pdf'), array('',''), $file->getFilename()); + } + + $list = array(); + foreach ($this->getAssignments() as $assignment) + $list[] = array( + $assignment->getTitle(), + $assignment->getPricePerHour() * $assignment->getHours(), + $assignment->getVAT() . "%", + $assignment->getPricePerHour() * $assignment->getHours() * (1 + $assignment->getVAT() / 100) + ); + foreach ($this->getDiscounts() as $discount) + $list[] = array( + $discount->getTitle(), + $discount->calculate(discount::SUBTOTAL), + $discount->getVAT() . "%", + $discount->calculate(discount::TOTAL) + ); + + $pdf = new correspondence(); + $pdf->SetContact($this->getContact()); + $pdf->SetTitle($pdf->_('invoice') . ' ' . $invoice_nr); + $pdf->AddPage(); + $pdf->correspondenceHeader(); + + $pdf->SetY(100); + $pdf->SetFont('','B',14); + $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); + $pdf->Cell(60,6, $pdf->_('invoice'),'B'); + $pdf->SetTextColor(0); + $pdf->Ln(); + + $width = array(90,25,20,25); + $subtotal = 0; + $btw = array(); + $total = 0; + + // Header + + $pdf->SetFont('','',9); + $pdf->Cell(60,4); + $pdf->Ln(); + $pdf->SetFont('','B'); + $pdf->Cell(30,4.5,$pdf->_('invoice-date')); + $pdf->SetFont('',''); + $pdf->Cell(50,4.5,date("d-m-Y", $this->invoice_date)); + $pdf->Ln(); + $pdf->SetFont('','B'); + $pdf->Cell(30,4.5,$pdf->_('invoice-nr')); + $pdf->SetFont('',''); + $pdf->Cell(50,4.5,$invoice_nr); + $pdf->Ln(); + $pdf->SetFont('','B'); + $pdf->Cell(30,4.5,$pdf->_('due-date')); + $pdf->SetFont('',''); + $pdf->Cell(50,4.5,date("d-m-Y",$this->invoice_date+3600*24*30)); + $pdf->Ln(); + $pdf->Cell(60,4.5,'','B'); + $pdf->Ln(); + + $pdf->SetY(140); + + // Table + + $pdf->SetFont('','B',11); + $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); + $pdf->Cell($width[0],7,$pdf->_('description'),'B'); + $pdf->Cell($width[1],7,$pdf->_('price-excl'),'B',0,'R'); + $pdf->Cell($width[2],7,$pdf->_('vat'),'B',0,'R'); + $pdf->Cell($width[3],7,$pdf->_('price-incl'),'B',0,'R'); + $pdf->SetTextColor(0); + $pdf->Ln(); + + $pdf->SetFont('',''); + foreach ($list as $row) { + $x = $pdf->getX(); + $y = $pdf->getY(); + $pdf->MultiCell($width[0],6,iconv('utf-8', 'iso-8859-1', $row[0]),0,'L'); + $newy = $pdf->getY(); + $pdf->SetXY($x + $width[0], $y); + $pdf->Cell($width[1],6,correspondence::valuta().number_format($row[1],2),'',0,'R'); + $pdf->Cell($width[2],6,round($row[2],0) . '%','',0,'R'); + $pdf->Cell($width[3],6,correspondence::valuta().number_format($row[3],2),'',0,'R'); + $pdf->Ln(); + $pdf->SetY($newy); + $pdf->addPageIfOnEnd(); + $subtotal += $row[1]; + if (!isset($btw[$row[2]])) $btw[$row[2]] = 0; + $btw[$row[2]] += $row[3] - $row[1]; + } + $total = $subtotal; + foreach ($btw as $m) { + $total += $m; + } + + $pdf->Cell(array_sum($width),5,'','T'); + $pdf->Ln(); + $pdf->Cell(array_sum($width),5); + $pdf->Ln(); + + $pdf->Cell($width[0],7); + $pdf->SetFont('','B'); + $pdf->Cell($width[1] + $width[2],7,$pdf->_('amount')); + $pdf->SetFont('',''); + $pdf->Cell($width[3],7,correspondence::valuta() . $this->calculate(self::SUBTOTAL),'',0,'R'); + $pdf->Ln(); + + foreach ($btw as $p => $m) { + $pdf->Cell($width[0],7); + $pdf->Cell($width[1] + $width[2],7,$pdf->_('vat') . ' '.round($p,0).'%'); + $pdf->Cell($width[3],7,correspondence::valuta() . number_format($m,2),'',0,'R'); + $pdf->Ln(); + } + + $pdf->Cell(array_sum($width),5); + $pdf->Ln(); + + $pdf->Cell($width[0],7); + $pdf->SetFont('','B'); + $pdf->Cell($width[1] + $width[2],7,$pdf->_('total')); + $pdf->SetFont('',''); + $pdf->Cell($width[3],7,correspondence::valuta() . $this->calculate(self::TOTAL),'T',0,'R'); + $pdf->Ln(); + + // Footer + + $pdf->Ln(); + $pdf->addPageIfOnEnd(); + if ($pdf->GetY() < 230) { + $pdf->SetY(230); + } + $oldY = $pdf->GetY(); + $pdf->Cell(45,20,'',1); + $pdf->Cell(12.5,20); + $pdf->Cell(45,20,'',1); + $pdf->Cell(12.5,20); + $pdf->Cell(45,20,'',1); + + $pdf->SetFont('','B',10); + $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); + $pdf->SetY($oldY + 3); + $pdf->Cell(5,5); + $pdf->Cell(40,5,$pdf->_('iban')); + $pdf->Cell(17.5,5); + $pdf->Cell(40,5,$pdf->_('invoice-nr')); + $pdf->Cell(17.5,5); + $pdf->Cell(40,5,$pdf->_('amount-due')); + $pdf->SetTextColor(0); + + $pdf->SetFont('','',8); + $pdf->Ln(); + $pdf->Ln(); + $oldY = $pdf->GetY(); + + $pdf->Cell(5,5); + $pdf->Cell(40,5, constants::invoice_iban); + $pdf->Cell(17.5,5); + $pdf->Cell(40,5,$invoice_nr); + $pdf->Cell(17.5,5); + $pdf->Cell(40,5,correspondence::valuta() . $this->calculate(self::TOTAL)); + + $pdf->SetY($oldY + 14); + + $pdf->SetFontSize(7); + $pdf->Cell(160,5,$pdf->_('request'),0,0,'C'); + $pdf->Ln(); + $pdf->Cell(160,5,str_replace('%%', constants::invoice_bic, $pdf->_('biccode')),0,0,'C'); + + if (file_exists($file->getFilenamePath())) { + unlink($file->getFilenamePath()); + } + $pdf->Output($file->getFilenamePath(),'F'); + chmod($file->getFilenamePath(),0644); + + return $file; + } +} diff --git a/classes/response.class.php b/classes/response.class.php deleted file mode 100644 index babf5ed..0000000 --- a/classes/response.class.php +++ /dev/null @@ -1,112 +0,0 @@ -. - */ - -/** - * Provides a standard to base all responses to be called with AJAX on - */ -class response { - /** The variable to keep the response in until output */ - private $response; - /** The variable to keep the HTTP response code in until output */ - private $http_response_code; - - /** - * Create a new instance - */ - public function __construct() { - $this->response = array(); - $this->http_response_code = 200; - } - - /** - * Set a variable of the response - * - * @param string $name The name of the variable to set - * @param string $value The (new) value for the variable - */ - public function __set($name, $value) { - $this->response[$name] = $value; - } - - /** - * Get a variable of the response - * - * @param string $name The name of the variable to get - * - * @return mixed The value of the variable - */ - public function __get($name) { - return $this->response[$name]; - } - - /** - * Check if a variable of the response is set - * - * @param string $name The name of the variable to check - * - * @return bool True if the variable exists, false otherwise - */ - public function __isset($name) { - return isset($this->response[$name]); - } - - /** - * Unset a variable of the response - * - * @param string $name The variable to unset - */ - public function __unset($name) { - unset($this->response[$name]); - } - - /** - * Get or set the HTTP response code - * - * If a parameter is provided, it is used as the new HTTP response code, and a bool is returned for success or failure. Otherwise, the current one is returned. - * - * @param int $code The new code - * - * @return int|bool True on successful change, false on unsuccesful change, int when the current code is returned - */ - public function http_response_code($code = null) { - if ($code === null) { - return $this->http_response_code; - } else { - if (http_response_code($code)) { - $this->http_response_code = $code; - return true; - } else { - return false; - } - } - } - - /** - * Output the response in json - * - * @return string The response in json format - */ - public function getJson() { - return json_encode($this->response); - } -} \ No newline at end of file diff --git a/classes/response.php b/classes/response.php new file mode 100644 index 0000000..babf5ed --- /dev/null +++ b/classes/response.php @@ -0,0 +1,112 @@ +. + */ + +/** + * Provides a standard to base all responses to be called with AJAX on + */ +class response { + /** The variable to keep the response in until output */ + private $response; + /** The variable to keep the HTTP response code in until output */ + private $http_response_code; + + /** + * Create a new instance + */ + public function __construct() { + $this->response = array(); + $this->http_response_code = 200; + } + + /** + * Set a variable of the response + * + * @param string $name The name of the variable to set + * @param string $value The (new) value for the variable + */ + public function __set($name, $value) { + $this->response[$name] = $value; + } + + /** + * Get a variable of the response + * + * @param string $name The name of the variable to get + * + * @return mixed The value of the variable + */ + public function __get($name) { + return $this->response[$name]; + } + + /** + * Check if a variable of the response is set + * + * @param string $name The name of the variable to check + * + * @return bool True if the variable exists, false otherwise + */ + public function __isset($name) { + return isset($this->response[$name]); + } + + /** + * Unset a variable of the response + * + * @param string $name The variable to unset + */ + public function __unset($name) { + unset($this->response[$name]); + } + + /** + * Get or set the HTTP response code + * + * If a parameter is provided, it is used as the new HTTP response code, and a bool is returned for success or failure. Otherwise, the current one is returned. + * + * @param int $code The new code + * + * @return int|bool True on successful change, false on unsuccesful change, int when the current code is returned + */ + public function http_response_code($code = null) { + if ($code === null) { + return $this->http_response_code; + } else { + if (http_response_code($code)) { + $this->http_response_code = $code; + return true; + } else { + return false; + } + } + } + + /** + * Output the response in json + * + * @return string The response in json format + */ + public function getJson() { + return json_encode($this->response); + } +} \ No newline at end of file diff --git a/conf.php b/conf.php index 22249c8..9c1cffc 100644 --- a/conf.php +++ b/conf.php @@ -57,7 +57,7 @@ $db_port = '3306'; * @param string $pClass The name of the class to load */ function __autoload($pClass) { - require_once("classes/$pClass.class.php"); + require_once("classes/$pClass.php"); } set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__)); -- cgit v1.2.3