diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..116f35f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +vendor +composer.lock +.idea \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b900af2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,29 @@ +language: php + +php: + - hhvm + - 7.0 + - 5.6 + - 5.5 + +matrix: + fast_finish: true + allow_failures: + - php: hhvm + +sudo: false + +install: composer install --no-interaction + +script: + - mkdir -p build/logs + - vendor/bin/phpunit --coverage-clover build/logs/clover.xml + +after_success: + - sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then php vendor/bin/coveralls -v; fi;' + +notifications: + email: + on_success: always + on_failure: always + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..6576e44 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +All notable changes to `webklex/laravel-pdfmerger` will be documented in this file. + +Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles. + +## [UNRELEASED] + +### Added +- new laravel-pdfmerger package diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6c13191 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Webklex + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..4242e78 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) 2016 Malte Goldenbaum + +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1ee54b6 --- /dev/null +++ b/README.md @@ -0,0 +1,83 @@ +# Laravel PDFMerger + +[![Latest Version on Packagist][ico-version]][link-packagist] +[![Software License][ico-license]](LICENSE.md) +[![Build Status][ico-travis]][link-travis] +[![Total Downloads][ico-downloads]][link-downloads] + + +## Install + +Via Composer + +``` bash +$ composer require webklex/laravel-pdfmerger +``` + +## Setup + +Add the service provider to the providers array in `config/app.php`. + +``` php +'providers' => [ + ... + Webklex\PDFMerger\Providers\PDFMergerServiceProvider::class +], + +'aliases' => [ + ... + 'PDFMerger' => Webklex\PDFMerger\Facades\PDFMergerFacade::class +] +``` + +## Usage + +``` php +use Webklex\PDFMerger\Facades\PDFMergerFacade as PDFMerger; + +$oPDF = PDFMerger::init(); + +$oPDF->setFileName('example.pdf'); +$oPDF->addPDF('first_pdf.pdf', '1'); +$oPDF->addPDF('second_pdf.pdf', 'all'); +$oPDF->merge(); +$oPDF->save('/somewhere/merged_result.pdf'); + +``` + +## Change log + +Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. + +## Testing + +``` bash +$ composer test +``` + +## Security + +If you discover any security related issues, please email github@webklex.com instead of using the issue tracker. + +## Credits + +- [Webklex][link-author] +- All Contributors + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. + +[ico-version]: https://img.shields.io/packagist/v/Webklex/PDFMerger.svg?style=flat-square +[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square +[ico-travis]: https://img.shields.io/travis/Webklex/translator/master.svg?style=flat-square +[ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/Webklex/PDFMerger.svg?style=flat-square +[ico-code-quality]: https://img.shields.io/scrutinizer/g/Webklex/PDFMerger.svg?style=flat-square +[ico-downloads]: https://img.shields.io/packagist/dt/Webklex/PDFMerger.svg?style=flat-square + +[link-packagist]: https://packagist.org/packages/Webklex/PDFMerger +[link-travis]: https://travis-ci.org/Webklex/PDFMerger +[link-scrutinizer]: https://scrutinizer-ci.com/g/Webklex/PDFMerger/code-structure +[link-code-quality]: https://scrutinizer-ci.com/g/Webklex/PDFMerger +[link-downloads]: https://packagist.org/packages/Webklex/PDFMerger +[link-author]: https://github.com/webklex \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..8a474e4 --- /dev/null +++ b/composer.json @@ -0,0 +1,49 @@ +{ + "name": "webklex/laravel-pdfmerger", + "type": "library", + "description": "Generic PDF merger for Laravel", + "keywords": [ + "webklex", + "laravel", + "pdf", + "merger", + "pdfmerger" + ], + "homepage": "https://github.com/webklex/pdfmerger", + "license": "MIT", + "authors": [ + { + "name": "Malte Goldenbaum", + "email": "github@webklex.com", + "role": "Developer" + } + ], + "require": { + "php": ">=5.5.9", + "illuminate/support": "~5.2", + "itbz/fpdi": "^1.6" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "scrutinizer/ocular": "~1.1", + "squizlabs/php_codesniffer": "~2.3" + }, + "autoload": { + "psr-4": { + "Webklex\\PDFMerger\\": "src/PDFMerger" + } + }, + "autoload-dev": { + "psr-4": { + "Webklex\\PDFMerger\\Test\\": "tests" + } + }, + "scripts": { + "test": "phpunit" + }, + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + } +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..cec65f3 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + tests + + + + + src/ + + + + + + + + + + diff --git a/src/PDFMerger/Facades/PDFMergerFacade.php b/src/PDFMerger/Facades/PDFMergerFacade.php new file mode 100644 index 0000000..bc18e87 --- /dev/null +++ b/src/PDFMerger/Facades/PDFMergerFacade.php @@ -0,0 +1,30 @@ +oFilesystem = $oFilesystem; + $this->oFPDI = new FPDI(); + $this->tmpFiles = collect([]); + + $this->init(); + } + + /** + * The class deconstructor method + */ + public function __destruct() { + $oFilesystem = $this->oFilesystem; + $this->tmpFiles->each(function($filePath) use($oFilesystem){ + $oFilesystem->delete($filePath); + }); + } + + /** + * Initialize a new internal instance of FPDI in order to prevent any problems with shared resources + * Please visit https://www.setasign.com/products/fpdi/manual/#p-159 for more information on this issue + * + * @return self + */ + public function init(){ + $this->oFPDI = new FPDI(); + $this->aFiles = collect([]); + return $this; + } + + /** + * Stream the merged PDF content + * + * @return string + */ + public function stream(){ + return $this->oFPDI->Output($this->fileName, 'I'); + } + + /** + * Download the merged PDF content + * + * @return string + */ + public function download(){ + return $this->oFPDI->Output($this->fileName, 'D'); + } + + /** + * Save the merged PDF content to the filesystem + * @param mixed $filePath + * + * @return string + */ + public function save($filePath = null){ + return $this->oFilesystem->put($filePath?$filePath:$this->fileName, $this->output()); + } + + /** + * Get the merged PDF content + * + * @return string + */ + public function output(){ + return $this->oFPDI->Output($this->fileName, 'S'); + } + + /** + * Set the final filename + * @param string $fileName + * + * @return string + */ + public function setFileName($fileName){ + $this->fileName = $fileName; + return $this; + } + + public function addString($string, $fileName, $pages = 'all', $orientation = null){ + + $filePath = storage_path('tmp/'.str_random(16).'.pdf'); + $this->oFilesystem->put($filePath, $string); + $this->tmpFiles->push($filePath); + + return $this->addPDF($filePath, $pages, $orientation); + } + + /** + * Add a PDF for inclusion in the merge with a valid file path. Pages should be formatted: 1,3,6, 12-16. + * @param string $filePath + * @param string $pages + * @param string $orientation + * + * @return self + * + * @throws \Exception if the given pages aren't correct + */ + public function addPDF($filePath, $pages = 'all', $orientation = null) { + if (file_exists($filePath)) { + if (!is_array($pages) && strtolower($pages) != 'all') { + throw new \Exception($filePath."'s pages could not be validated"); + } + + $this->aFiles->push([ + 'name' => $filePath, + 'pages' => $pages, + 'orientation' => $orientation + ]); + } else { + throw new \Exception("Could not locate PDF on '$filePath'"); + } + + return $this; + } + + /** + * Merges your provided PDFs and outputs to specified location. + * @param string $orientation + * + * @return void + * + * @throws \Exception if there are now PDFs to merge + */ + public function merge($orientation = 'P') { + + if ($this->aFiles->count() == 0) { + throw new \Exception("No PDFs to merge."); + } + + $oFPDI = $this->oFPDI; + + $this->aFiles->each(function($file) use($oFPDI, $orientation){ + $file['orientation'] = !is_null($file['orientation'])?$orientation:$file['orientation']; + if ($file['pages'] == 'all') { + $count = $oFPDI->setSourceFile($file['name']); + + for ($i = 1; $i <= $count; $i++) { + $template = $oFPDI->importPage($i); + $size = $oFPDI->getTemplateSize($template); + + $oFPDI->AddPage($file['orientation'], [$size['w'], $size['h']]); + $oFPDI->useTemplate($template); + } + } else { + foreach ($file['pages'] as $page) { + if (!$template = $oFPDI->importPage($page)) { + throw new \Exception("Could not load page '$page' in PDF '".$file['name']."'. Check that the page exists."); + } + $size = $oFPDI->getTemplateSize($template); + + $oFPDI->AddPage($file['orientation'], [$size['w'], $size['h']]); + $oFPDI->useTemplate($template); + } + } + }); + } +} \ No newline at end of file diff --git a/src/PDFMerger/Providers/PDFMergerServiceProvider.php b/src/PDFMerger/Providers/PDFMergerServiceProvider.php new file mode 100755 index 0000000..8ecb38c --- /dev/null +++ b/src/PDFMerger/Providers/PDFMergerServiceProvider.php @@ -0,0 +1,43 @@ +app->singleton('PDFMerger', function ($app) { + $oPDFMerger = new PDFMerger($app['files']); + return $oPDFMerger; + }); + } +} \ No newline at end of file