--- /dev/null
+{\r
+ "require": {\r
+ "php-mime-mail-parser/php-mime-mail-parser": "2.11.1"\r
+ }\r
+}\r
$db->google_search_api->date('integer', 0, false);\r
$db->google_search_api->primary('pk_google_search_api', 'request');\r
\r
+ // Table Bourbon\r
+ $db->bourbon_suggestions->from('varchar', 256, false);\r
+ $db->bourbon_suggestions->date('integer', 0, false);\r
+ $db->bourbon_suggestions->type('varchar', 256, false);\r
+ $db->bourbon_suggestions->suggestion('text', 0, false);\r
+ $db->bourbon_suggestions->page('varchar', 256, false);\r
+\r
try {\r
$dbi = new CubeDbStruct($this->con);\r
$dbi->synchronize($db);\r
public function getFluidbookPage($id, $page)
{
global $core;
+ $this->outputXML = false;
$id = $this->callArgs[0];
$page = $this->callArgs[1];
}
}
+
+ public function bourbonSuggestion()
+ {
+ global $core;
+ try {
+ $mail = new PhpMimeMailParser\Parser();
+ $mail->setText(base64_decode($_POST['email']));
+ $from = $mail->getAddresses('from');
+ $from = $from[0]['address'];
+
+
+ $attachments = $mail->getAttachments();
+ foreach ($attachments as $k => $attachment) {
+ if ($attachment->getFilename() !== 'suggestion.txt') {
+ continue;
+ }
+ $suggestion = $attachment->getContent();
+ $parts = explode('/|!/', $suggestion);
+ $c = $core->con->openCursor('bourbon_suggestions');
+ $c->type = $parts[2];
+ $c->suggestion = $parts[3];
+ $c->date = round($parts[1]/1000);
+ $c->from = $from;
+ $c->page = $parts[0];
+ $c->insert();
+
+ break;
+ }
+ file_put_contents('/tmp/bourbonSuggestion', print_r($mail, true));
+ file_put_contents('/tmp/bourbonSuggestionAttach', print_r($attachments, true));
+ } catch (Exception $e) {
+ file_put_contents('/tmp/bourbonSuggestion', print_r($e, true));
+ }
+
+ $body = "Hello,\r\nThis automatic message confirm that your suggestion has been received.\r\nPlease do not reply to this e-mail,\r\nThank you";
+
+ $ack = new Zend_Mail();
+ $ack->setFrom('no-reply@bourbonoffshore.com');
+ $ack->setSubject('Suggestion ackknowledge');
+ $ack->setBodyText($body);
+
+ $ack->addTo($from);
+ $ack->send();
+ }
+
+ public function downloadBourbonSuggestions58412()
+ {
+ global $core;
+ $this->outputXML = false;
+ $r = $core->con->select('SELECT * FROM bourbon_suggestions ORDER BY date DESC');
+ $excel = new PHPExcel();
+ $excel->setActiveSheetIndex(0);
+ $defaultStyle = $excel->getDefaultStyle();
+ $defaultStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
+ $defaultStyle->getAlignment()->setWrapText(true);
+ $s = $excel->getActiveSheet();
+ $s->setTitle('Suggestions');
+ $s->setCellValueByColumnAndRow(0, 1, 'Sender');
+ $s->setCellValueByColumnAndRow(1, 1, 'Date');
+ $s->setCellValueByColumnAndRow(2, 1, 'Type');
+ $s->setCellValueByColumnAndRow(3, 1, 'Page');
+ $s->setCellValueByColumnAndRow(4, 1, 'Suggestion content');
+
+ $line = 2;
+ while ($r->fetch()) {
+ $date = date('Y-m-d H:i:s', round($r->date));
+
+ $s->setCellValueByColumnAndRow(0, $line, $r->from);
+ $s->setCellValueByColumnAndRow(1, $line, $date);
+ $s->setCellValueByColumnAndRow(2, $line, $r->type);
+ $s->setCellValueByColumnAndRow(3, $line, $r->page);
+ $s->setCellValueByColumnAndRow(4, $line, $r->suggestion);
+
+ $line++;
+ }
+
+ for ($i = 0; $i <= 4; $i++) {
+ $s->getColumnDimensionByColumn($i)->setAutoSize(true);
+ }
+
+
+ header('Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+ header('Content-Disposition: attachment;filename="fluidbook-suggestions.xlsx"');
+ header('Cache-Control: max-age=0');
+ // If you're serving to IE 9, then the following may be needed
+ header('Cache-Control: max-age=1');
+ // If you're serving to IE over SSL, then the following may be needed
+ header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
+ header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
+ header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
+ header('Pragma: public'); // HTTP/1.0
+
+ $writer = PHPExcel_IOFactory::createWriter($excel, 'Excel2007');
+ ob_end_clean();
+ $writer->save('php://output');
+ exit;
+
+ }
}
<?php
+require_once (dirname(__FILE__) . '/vendor/autoload.php');
require_once(dirname(__FILE__) . '/inc/prepend.php');
+
ob_start();
header('Access-Control-Allow-Origin: *');
--- /dev/null
+<?php
+
+// autoload.php @generated by Composer
+
+require_once __DIR__ . '/composer/autoload_real.php';
+
+return ComposerAutoloaderInit920111649f7e87249f1f2fbc0fd23976::getLoader();
--- /dev/null
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ * Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @see http://www.php-fig.org/psr/psr-0/
+ * @see http://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ // PSR-4
+ private $prefixLengthsPsr4 = array();
+ private $prefixDirsPsr4 = array();
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ private $prefixesPsr0 = array();
+ private $fallbackDirsPsr0 = array();
+
+ private $useIncludePath = false;
+ private $classMap = array();
+ private $classMapAuthoritative = false;
+ private $missingClasses = array();
+ private $apcuPrefix;
+
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
+ }
+
+ return array();
+ }
+
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param array $classMap Class to filename map
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ (array) $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ (array) $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 base directories
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
+ *
+ * @param string|null $apcuPrefix
+ */
+ public function setApcuPrefix($apcuPrefix)
+ {
+ $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
+ }
+
+ /**
+ * The APCu prefix in use, or null if APCu caching is not enabled.
+ *
+ * @return string|null
+ */
+ public function getApcuPrefix()
+ {
+ return $this->apcuPrefix;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return bool|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ includeFile($file);
+
+ return true;
+ }
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
+ return false;
+ }
+ if (null !== $this->apcuPrefix) {
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
+ if ($hit) {
+ return $file;
+ }
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if (false === $file && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if (null !== $this->apcuPrefix) {
+ apcu_add($this->apcuPrefix.$class, $file);
+ }
+
+ if (false === $file) {
+ // Remember that this class does not exist.
+ $this->missingClasses[$class] = true;
+ }
+
+ return $file;
+ }
+
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ $subPath = $class;
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
+ $subPath = substr($subPath, 0, $lastPos);
+ $search = $subPath . '\\';
+ if (isset($this->prefixDirsPsr4[$search])) {
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
+ if (file_exists($file = $dir . $pathEnd)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+
+ return false;
+ }
+}
+
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ */
+function includeFile($file)
+{
+ include $file;
+}
--- /dev/null
+
+Copyright (c) Nils Adermann, Jordi Boggiano
+
+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.
+
--- /dev/null
+<?php
+
+// autoload_classmap.php @generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+);
--- /dev/null
+<?php
+
+// autoload_namespaces.php @generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+);
--- /dev/null
+<?php
+
+// autoload_psr4.php @generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+ 'PhpMimeMailParser\\' => array($vendorDir . '/php-mime-mail-parser/php-mime-mail-parser/src'),
+);
--- /dev/null
+<?php
+
+// autoload_real.php @generated by Composer
+
+class ComposerAutoloaderInit920111649f7e87249f1f2fbc0fd23976
+{
+ private static $loader;
+
+ public static function loadClassLoader($class)
+ {
+ if ('Composer\Autoload\ClassLoader' === $class) {
+ require __DIR__ . '/ClassLoader.php';
+ }
+ }
+
+ public static function getLoader()
+ {
+ if (null !== self::$loader) {
+ return self::$loader;
+ }
+
+ spl_autoload_register(array('ComposerAutoloaderInit920111649f7e87249f1f2fbc0fd23976', 'loadClassLoader'), true, true);
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader();
+ spl_autoload_unregister(array('ComposerAutoloaderInit920111649f7e87249f1f2fbc0fd23976', 'loadClassLoader'));
+
+ $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
+ if ($useStaticLoader) {
+ require_once __DIR__ . '/autoload_static.php';
+
+ call_user_func(\Composer\Autoload\ComposerStaticInit920111649f7e87249f1f2fbc0fd23976::getInitializer($loader));
+ } else {
+ $map = require __DIR__ . '/autoload_namespaces.php';
+ foreach ($map as $namespace => $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+ }
+
+ $loader->register(true);
+
+ return $loader;
+ }
+}
--- /dev/null
+<?php
+
+// autoload_static.php @generated by Composer
+
+namespace Composer\Autoload;
+
+class ComposerStaticInit920111649f7e87249f1f2fbc0fd23976
+{
+ public static $prefixLengthsPsr4 = array (
+ 'P' =>
+ array (
+ 'PhpMimeMailParser\\' => 18,
+ ),
+ );
+
+ public static $prefixDirsPsr4 = array (
+ 'PhpMimeMailParser\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/php-mime-mail-parser/php-mime-mail-parser/src',
+ ),
+ );
+
+ public static function getInitializer(ClassLoader $loader)
+ {
+ return \Closure::bind(function () use ($loader) {
+ $loader->prefixLengthsPsr4 = ComposerStaticInit920111649f7e87249f1f2fbc0fd23976::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInit920111649f7e87249f1f2fbc0fd23976::$prefixDirsPsr4;
+
+ }, null, ClassLoader::class);
+ }
+}
--- /dev/null
+[
+ {
+ "name": "php-mime-mail-parser/php-mime-mail-parser",
+ "version": "2.11.1",
+ "version_normalized": "2.11.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git",
+ "reference": "4769e942ed0dbbdd7882fc390b119d625463c8af"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/4769e942ed0dbbdd7882fc390b119d625463c8af",
+ "reference": "4769e942ed0dbbdd7882fc390b119d625463c8af",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mailparse": "*",
+ "php": "^5.4.0 || ^7.0"
+ },
+ "replace": {
+ "exorus/php-mime-mail-parser": "*",
+ "messaged/php-mime-mail-parser": "*"
+ },
+ "require-dev": {
+ "phpunit/php-token-stream": "^1.3.0",
+ "phpunit/phpunit": "^4.0 || ^5.0",
+ "satooshi/php-coveralls": "0.*",
+ "squizlabs/php_codesniffer": "2.*"
+ },
+ "time": "2018-04-30T05:55:59+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "PhpMimeMailParser\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "bucabay",
+ "email": "gabe@fijiwebdesign.com",
+ "homepage": "http://www.fijiwebdesign.com",
+ "role": "Developer"
+ },
+ {
+ "name": "eXorus",
+ "email": "exorus.spam@gmail.com",
+ "homepage": "https://github.com/eXorus/",
+ "role": "Developer"
+ },
+ {
+ "name": "M.Valinskis",
+ "email": "M.Valins@gmail.com",
+ "homepage": "https://code.google.com/p/php-mime-mail-parser",
+ "role": "Developer"
+ },
+ {
+ "name": "eugene.emmett.wood",
+ "email": "gene_w@cementhorizon.com",
+ "homepage": "https://code.google.com/p/php-mime-mail-parser",
+ "role": "Developer"
+ },
+ {
+ "name": "alknetso",
+ "email": "alkne@gmail.com",
+ "homepage": "https://code.google.com/p/php-mime-mail-parser",
+ "role": "Developer"
+ }
+ ],
+ "description": "Fully Tested Mailparse Extension Wrapper for PHP 5.4+",
+ "homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser",
+ "keywords": [
+ "MimeMailParser",
+ "mail",
+ "mailparse",
+ "mime"
+ ]
+ }
+]
--- /dev/null
+The MIT License (MIT)
+
+Copyright (c) 2016 Vincent Dauce
+
+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.
--- /dev/null
+# php-mime-mail-parser
+
+A fully tested mailparse extension wrapper for PHP 5.4+
+
+[](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases)
+[](https://packagist.org/packages/php-mime-mail-parser/php-mime-mail-parser)
+[](LICENSE)
+
+## Why?
+
+This extension can be used to...
+ * Parse and read email from Postfix
+ * Create webmail
+ * Store email information such a subject, HTML body, attachments, and etc. into a database
+
+## Is it reliable?
+
+Yes. All known issues have been reproduced, fixed and tested.
+
+We use Travis CI to help ensure code quality. You can see real-time statistics below:
+
+[](https://travis-ci.org/php-mime-mail-parser/php-mime-mail-parser)
+[](https://coveralls.io/r/php-mime-mail-parser/php-mime-mail-parser)
+[](https://scrutinizer-ci.com/g/php-mime-mail-parser/php-mime-mail-parser)
+
+## How do I install it?
+
+The easiest way is via [Composer](https://getcomposer.org/).
+
+To install the latest version of PHP MIME Mail Parser, run the command below:
+
+ composer require php-mime-mail-parser/php-mime-mail-parser
+
+## Requirements
+
+The following versions of PHP are supported:
+
+* PHP 5.4
+* PHP 5.5
+* PHP 5.6
+* PHP 7
+* HHVM
+
+```
+sudo apt install php-cli php-pear php-dev php-mbstring
+```
+
+Make sure you have the mailparse extension (http://php.net/manual/en/book.mailparse.php) properly installed. The command line `php -m | grep mailparse` need to return "mailparse" else install it:
+* PHP version > 7.0: mailparse
+* PHP version < 7.0: mailparse 2.1.6
+
+Follow this steps to install mailparse:
+
+* Compile in the temp folder the extension mailparse or mailparse-2.1.6 (workaround because pecl install doesn't work yet)
+```
+cd
+pecl download mailparse
+tar -xvf mailparse-3.0.2.tgz
+cd mailparse-3.0.2/
+phpize
+./configure
+sed -i 's/#if\s!HAVE_MBSTRING/#ifndef MBFL_MBFILTER_H/' ./mailparse.c
+make
+sudo mv modules/mailparse.so /usr/lib/php/20160303/
+```
+* Add the extension mailparse and activate it
+```
+echo "extension=mailparse.so" | sudo tee /etc/php/7.1/mods-available/mailparse.ini
+sudo phpenmod mailparse
+```
+
+On Windows, you need to download mailparse DLL from http://pecl.php.net/package/mailparse and add the line "extension=php_mailparse.dll" to php.ini accordingly.
+
+## How do I use it?
+
+```php
+<?php
+// Include the library first
+require_once __DIR__.'/vendor/autoload.php';
+
+$path = 'path/to/mail.txt';
+$Parser = new PhpMimeMailParser\Parser();
+
+// There are four methods available to indicate which mime mail to parse.
+// You only need to use one of the following four:
+
+// 1. Specify a file path to the mime mail.
+$Parser->setPath($path);
+
+// 2. Specify a php file resource (stream) to the mime mail.
+$Parser->setStream(fopen($path, "r"));
+
+// 3. Specify the raw mime mail text.
+$Parser->setText(file_get_contents($path));
+
+// 4. Specify a stream to work with mail server
+$Parser->setStream(fopen("php://stdin", "r"));
+
+// Once we've indicated where to find the mail, we can parse out the data
+$to = $Parser->getHeader('to'); // "test" <test@example.com>, "test2" <test2@example.com>
+$addressesTo = $Parser->getAddresses('to'); //Return an array : [["display"=>"test", "address"=>"test@example.com", false],["display"=>"test2", "address"=>"test2@example.com", false]]
+
+$from = $Parser->getHeader('from'); // "test" <test@example.com>
+$addressesFrom = $Parser->getAddresses('from'); //Return an array : [["display"=>"test", "address"=>"test@example.com", "is_group"=>false]]
+
+$subject = $Parser->getHeader('subject');
+
+$text = $Parser->getMessageBody('text');
+
+$html = $Parser->getMessageBody('html');
+$htmlEmbedded = $Parser->getMessageBody('htmlEmbedded'); //HTML Body included data
+
+$stringHeaders = $Parser->getHeadersRaw(); // Get all headers as a string, no charset conversion
+$arrayHeaders = $Parser->getHeaders(); // Get all headers as an array, with charset conversion
+
+// Pass in a writeable path to save attachments
+$attach_dir = '/path/to/save/attachments/'; // Be sure to include the trailing slash
+$include_inline = true; // Optional argument to include inline attachments (default: true)
+$Parser->saveAttachments($attach_dir [,$include_inline]);
+
+// Get an array of Attachment items from $Parser
+$attachments = $Parser->getAttachments([$include_inline]);
+
+// Loop through all the Attachments
+if (count($attachments) > 0) {
+ foreach ($attachments as $attachment) {
+ echo 'Filename : '.$attachment->getFilename().'<br />'; // logo.jpg
+ echo 'Filesize : '.filesize($attach_dir.$attachment->getFilename()).'<br />'; // 1000
+ echo 'Filetype : '.$attachment->getContentType().'<br />'; // image/jpeg
+ echo 'MIME part string : '.$attachment->getMimePartStr().'<br />'; // (the whole MIME part of the attachment)
+ }
+}
+
+?>
+```
+
+Next you need to forward emails to this script above. For that I'm using [Postfix](http://www.postfix.org/) like a mail server, you need to configure /etc/postfix/master.cf
+
+Add this line at the end of the file (specify myhook to send all emails to the script test.php)
+```
+myhook unix - n n - - pipe
+ flags=F user=www-data argv=php -c /etc/php5/apache2/php.ini -f /var/www/test.php ${sender} ${size} ${recipient}
+```
+
+Edit this line (register myhook)
+```
+smtp inet n - - - - smtpd
+ -o content_filter=myhook:dummy
+```
+
+The php script must use the fourth method to work with this configuration.
+
+
+## Can I contribute?
+
+Feel free to contribute!
+
+ git clone https://github.com/php-mime-mail-parser/php-mime-mail-parser
+ cd php-mime-mail-parser
+ composer install
+ ./vendor/bin/phpunit
+
+If you report an issue, please provide the raw email that triggered it. This helps us reproduce the issue and fix it more quickly.
+
+### License
+
+The php-mime-mail-parser/php-mime-mail-parser is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
--- /dev/null
+{
+ "name": "php-mime-mail-parser/php-mime-mail-parser",
+ "type": "library",
+ "description": "Fully Tested Mailparse Extension Wrapper for PHP 5.4+",
+ "keywords": ["mime", "mail", "mailparse", "MimeMailParser"],
+ "homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser",
+ "license": "MIT",
+ "authors": [
+ {
+ "name":"eXorus",
+ "email":"exorus.spam@gmail.com",
+ "homepage":"https://github.com/eXorus/",
+ "role":"Developer"
+ },
+ {
+ "name":"M.Valinskis",
+ "email":"M.Valins@gmail.com",
+ "homepage":"https://code.google.com/p/php-mime-mail-parser",
+ "role":"Developer"
+ },
+ {
+ "name":"eugene.emmett.wood",
+ "email":"gene_w@cementhorizon.com",
+ "homepage":"https://code.google.com/p/php-mime-mail-parser",
+ "role":"Developer"
+ },
+ {
+ "name":"alknetso",
+ "email":"alkne@gmail.com",
+ "homepage":"https://code.google.com/p/php-mime-mail-parser",
+ "role":"Developer"
+ },
+ {
+ "name":"bucabay",
+ "email":"gabe@fijiwebdesign.com",
+ "homepage":"http://www.fijiwebdesign.com",
+ "role":"Developer"
+ }
+ ],
+ "repository":{
+ "type":"git",
+ "url":"https://github.com/php-mime-mail-parser/php-mime-mail-parser.git"
+ },
+ "require": {
+ "php": "^5.4.0 || ^7.0",
+ "ext-mailparse": "*"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0 || ^5.0",
+ "phpunit/php-token-stream": "^1.3.0",
+ "satooshi/php-coveralls": "0.*",
+ "squizlabs/PHP_CodeSniffer": "2.*"
+ },
+ "replace": {
+ "exorus/php-mime-mail-parser": "*",
+ "messaged/php-mime-mail-parser": "*"
+ },
+ "autoload": {
+ "psr-4": { "PhpMimeMailParser\\": "src/" }
+ }
+}
--- /dev/null
+<?php
+/**
+ * @link http://php.net/manual/en/mailparse.constants.php
+ */
+define('MAILPARSE_EXTRACT_OUTPUT', 0);
+
+/**
+ * @link http://php.net/manual/en/mailparse.constants.php
+ */
+define('MAILPARSE_EXTRACT_STREAM', 1);
+
+/**
+ * @link http://php.net/manual/en/mailparse.constants.php
+ */
+define('MAILPARSE_EXTRACT_RETURN', 2);
+
+/**
+ * Parses a file. This is the optimal way of parsing a mail file that you have on
+ * disk.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-parse-file.php
+ *
+ * @param string $filename Path to the file holding the message. The file is opened
+ * and streamed through the parser
+ *
+ * @return resource Returns a MIME resource representing the structure, or false on error
+ */
+function mailparse_msg_parse_file($filename)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-get-part.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ * @param string $mimesection
+ *
+ * @return resource
+ */
+function mailparse_msg_get_part($mimemail, $mimesection)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-get-structure.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ *
+ * @return array
+ */
+function mailparse_msg_get_structure($mimemail)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-get-part-data.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ *
+ * @return array
+ */
+function mailparse_msg_get_part_data($mimemail)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-extract-part.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ * @param string $msgbody
+ * @param callable $callbackfunc
+ *
+ * @return void
+ */
+function mailparse_msg_extract_part($mimemail, $msgbody, $callbackfunc)
+{
+}
+
+/**
+ * Extracts/decodes a message section from the supplied filename.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-extract-part-file.php
+ *
+ * @param resource $mimemail A valid MIME resource, created with
+ * mailparse_msg_create
+ * @param mixed $filename Can be a file name or a valid stream resource
+ * @param callable $callbackfunc If set, this must be either a valid callback that
+ * will be passed the extracted section, or null to make this function return the
+ * extracted section
+ *
+ * @return string If $callbackfunc is not null returns true on success
+ */
+function mailparse_msg_extract_part_file($mimemail, $filename, $callbackfunc = false)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-extract-whole-part-file.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ * @param string $filename
+ * @param callable $callbackfunc
+ *
+ * @return string
+ */
+function mailparse_msg_extract_whole_part_file($mimemail, $filename, $callbackfunc)
+{
+}
+
+/**
+ * Create a MIME mail resource.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-create.php
+ * @return resource Returns a handle that can be used to parse a message
+ */
+function mailparse_msg_create()
+{
+}
+
+/**
+ * Frees a MIME resource.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-free.php
+ *
+ * @param resource $mimemail A valid MIME resource allocated by
+ * mailparse_msg_create or mailparse_msg_parse_file
+ *
+ * @return bool
+ */
+function mailparse_msg_free($mimemail)
+{
+}
+
+/**
+ * Incrementally parse data into the supplied mime mail resource.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-parse.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ * @param string $data
+ *
+ * @return bool
+ */
+function mailparse_msg_parse($mimemail, $data)
+{
+}
+
+/**
+ * Parses a RFC 822 compliant recipient list, such as that found in the To: header.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-rfc822-parse-addresses.php
+ *
+ * @param string $addresses A string containing addresses, like in: Wez Furlong
+ * wez@example.com, doe@example.com
+ *
+ * @return array Returns an array of associative arrays with the following keys for each
+ * recipient: display The recipient name, for display purpose. If this part is not
+ * set for a recipient, this key will hold the same value as address. address The
+ * email address is_group true if the recipient is a newsgroup, false otherwise
+ */
+function mailparse_rfc822_parse_addresses($addresses)
+{
+}
+
+/**
+ * Figures out the best way of encoding the content read from the given file
+ * pointer.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-determine-best-xfer-encoding.php
+ *
+ * @param resource $fp A valid file pointer, which must be seek-able
+ *
+ * @return string Returns one of the character encodings supported by the mbstring module
+ */
+function mailparse_determine_best_xfer_encoding($fp)
+{
+}
+
+/**
+ * Streams data from the source file pointer, apply $encoding and write to the
+ * destination file pointer.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-stream-encode.php
+ *
+ * @param resource $sourcefp A valid file handle. The file is streamed through the
+ * parser
+ * @param resource $destfp The destination file handle in which the encoded data
+ * will be written
+ * @param string $encoding One of the character encodings supported by the mbstring
+ * module
+ *
+ * @return bool
+ */
+function mailparse_stream_encode($sourcefp, $destfp, $encoding)
+{
+}
+
+/**
+ * Scans the data from the given file pointer and extract each embedded uuencoded
+ * file into a temporary file.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-uudecode-all.php
+ *
+ * @param resource $fp A valid file pointer
+ *
+ * @return array Returns an array of associative arrays listing filename information.
+ * filename Path to the temporary file name created origfilename The original
+ * filename, for uuencoded parts only The first filename entry is the message body.
+ * The next entries are the decoded uuencoded files
+ */
+function mailparse_uudecode_all($fp)
+{
+}
+
+/**
+ * @return
+ */
+function mailparse_test()
+{
+}
+
+class mimemessage
+{
+ /**
+ * @return
+ */
+ public function mimemessage()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function get_child()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function get_child_count()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function get_parent()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function extract_headers()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function extract_body()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function enum_uue()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function extract_uue()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function remove()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function add_child()
+ {
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit colors="true" bootstrap="vendor/autoload.php">
+ <testsuite name="eXorus PhpMimeMailParser Test Suite">
+ <directory suffix="Test.php">tests</directory>
+ </testsuite>
+</phpunit>
--- /dev/null
+<?php
+
+namespace PhpMimeMailParser;
+
+/**
+ * Attachment of php-mime-mail-parser
+ *
+ * Fully Tested Mailparse Extension Wrapper for PHP 5.4+
+ *
+ */
+class Attachment
+{
+ /**
+ * @var string $filename Filename
+ */
+ protected $filename;
+
+ /**
+ * @var string $contentType Mime Type
+ */
+ protected $contentType;
+
+ /**
+ * @var string $content File Content
+ */
+ protected $content;
+
+ /**
+ * @var string $contentDisposition Content-Disposition (attachment or inline)
+ */
+ protected $contentDisposition;
+
+ /**
+ * @var string $contentId Content-ID
+ */
+ protected $contentId;
+
+ /**
+ * @var array $headers An Array of the attachment headers
+ */
+ protected $headers;
+
+ /**
+ * @var resource $stream
+ */
+ protected $stream;
+
+ /**
+ * @var string $mimePartStr
+ */
+ protected $mimePartStr;
+
+ /**
+ * Attachment constructor.
+ *
+ * @param string $filename
+ * @param string $contentType
+ * @param resource $stream
+ * @param string $contentDisposition
+ * @param string $contentId
+ * @param array $headers
+ * @param string $mimePartStr
+ */
+ public function __construct(
+ $filename,
+ $contentType,
+ $stream,
+ $contentDisposition = 'attachment',
+ $contentId = '',
+ $headers = [],
+ $mimePartStr = ''
+ ) {
+ $this->filename = $filename;
+ $this->contentType = $contentType;
+ $this->stream = $stream;
+ $this->content = null;
+ $this->contentDisposition = $contentDisposition;
+ $this->contentId = $contentId;
+ $this->headers = $headers;
+ $this->mimePartStr = $mimePartStr;
+ }
+
+ /**
+ * retrieve the attachment filename
+ *
+ * @return string
+ */
+ public function getFilename()
+ {
+ return $this->filename;
+ }
+
+ /**
+ * Retrieve the Attachment Content-Type
+ *
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->contentType;
+ }
+
+ /**
+ * Retrieve the Attachment Content-Disposition
+ *
+ * @return string
+ */
+ public function getContentDisposition()
+ {
+ return $this->contentDisposition;
+ }
+
+ /**
+ * Retrieve the Attachment Content-ID
+ *
+ * @return string
+ */
+ public function getContentID()
+ {
+ return $this->contentId;
+ }
+
+ /**
+ * Retrieve the Attachment Headers
+ *
+ * @return array
+ */
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Get a handle to the stream
+ *
+ * @return stream
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+
+ /**
+ * Read the contents a few bytes at a time until completed
+ * Once read to completion, it always returns false
+ *
+ * @param int $bytes (default: 2082)
+ *
+ * @return string|bool
+ */
+ public function read($bytes = 2082)
+ {
+ return feof($this->stream) ? false : fread($this->stream, $bytes);
+ }
+
+ /**
+ * Retrieve the file content in one go
+ * Once you retrieve the content you cannot use MimeMailParser_attachment::read()
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ if ($this->content === null) {
+ fseek($this->stream, 0);
+ while (($buf = $this->read()) !== false) {
+ $this->content .= $buf;
+ }
+ }
+
+ return $this->content;
+ }
+
+ /**
+ * Get mime part string for this attachment
+ *
+ * @return string
+ */
+ public function getMimePartStr()
+ {
+ return $this->mimePartStr;
+ }
+}
--- /dev/null
+<?php namespace PhpMimeMailParser;
+
+use PhpMimeMailParser\Contracts\CharsetManager;
+
+class Charset implements CharsetManager
+{
+ /**
+ * Charset Aliases
+ */
+ private $charsetAlias = [
+ 'ascii' => 'us-ascii',
+ 'us-ascii' => 'us-ascii',
+ 'ansi_x3.4-1968' => 'us-ascii',
+ '646' => 'us-ascii',
+ 'iso-8859-1' => 'ISO-8859-1',
+ 'iso-8859-2' => 'ISO-8859-2',
+ 'iso-8859-3' => 'ISO-8859-3',
+ 'iso-8859-4' => 'ISO-8859-4',
+ 'iso-8859-5' => 'ISO-8859-5',
+ 'iso-8859-6' => 'ISO-8859-6',
+ 'iso-8859-6-i' => 'ISO-8859-6-I',
+ 'iso-8859-6-e' => 'ISO-8859-6-E',
+ 'iso-8859-7' => 'ISO-8859-7',
+ 'iso-8859-8' => 'ISO-8859-8',
+ 'iso-8859-8-i' => 'ISO-8859-8',
+ 'iso-8859-8-e' => 'ISO-8859-8-E',
+ 'iso-8859-9' => 'ISO-8859-9',
+ 'iso-8859-10' => 'ISO-8859-10',
+ 'iso-8859-11' => 'ISO-8859-11',
+ 'iso-8859-13' => 'ISO-8859-13',
+ 'iso-8859-14' => 'ISO-8859-14',
+ 'iso-8859-15' => 'ISO-8859-15',
+ 'iso-8859-16' => 'ISO-8859-16',
+ 'iso-ir-111' => 'ISO-IR-111',
+ 'iso-2022-cn' => 'ISO-2022-CN',
+ 'iso-2022-cn-ext' => 'ISO-2022-CN',
+ 'iso-2022-kr' => 'ISO-2022-KR',
+ 'iso-2022-jp' => 'ISO-2022-JP',
+ 'utf-16be' => 'UTF-16BE',
+ 'utf-16le' => 'UTF-16LE',
+ 'utf-16' => 'UTF-16',
+ 'windows-1250' => 'windows-1250',
+ 'windows-1251' => 'windows-1251',
+ 'windows-1252' => 'windows-1252',
+ 'windows-1253' => 'windows-1253',
+ 'windows-1254' => 'windows-1254',
+ 'windows-1255' => 'windows-1255',
+ 'windows-1256' => 'windows-1256',
+ 'windows-1257' => 'windows-1257',
+ 'windows-1258' => 'windows-1258',
+ 'ibm866' => 'IBM866',
+ 'ibm850' => 'IBM850',
+ 'ibm852' => 'IBM852',
+ 'ibm855' => 'IBM855',
+ 'ibm857' => 'IBM857',
+ 'ibm862' => 'IBM862',
+ 'ibm864' => 'IBM864',
+ 'utf-8' => 'UTF-8',
+ 'utf-7' => 'UTF-7',
+ 'shift_jis' => 'Shift_JIS',
+ 'big5' => 'Big5',
+ 'euc-jp' => 'EUC-JP',
+ 'euc-kr' => 'EUC-KR',
+ 'gb2312' => 'GB2312',
+ 'gb18030' => 'gb18030',
+ 'viscii' => 'VISCII',
+ 'koi8-r' => 'KOI8-R',
+ 'koi8_r' => 'KOI8-R',
+ 'cskoi8r' => 'KOI8-R',
+ 'koi' => 'KOI8-R',
+ 'koi8' => 'KOI8-R',
+ 'koi8-u' => 'KOI8-U',
+ 'tis-620' => 'TIS-620',
+ 't.61-8bit' => 'T.61-8bit',
+ 'hz-gb-2312' => 'HZ-GB-2312',
+ 'big5-hkscs' => 'Big5-HKSCS',
+ 'gbk' => 'gbk',
+ 'cns11643' => 'x-euc-tw',
+ 'x-imap4-modified-utf7' => 'x-imap4-modified-utf7',
+ 'x-euc-tw' => 'x-euc-tw',
+ 'x-mac-ce' => 'x-mac-ce',
+ 'x-mac-turkish' => 'x-mac-turkish',
+ 'x-mac-greek' => 'x-mac-greek',
+ 'x-mac-icelandic' => 'x-mac-icelandic',
+ 'x-mac-croatian' => 'x-mac-croatian',
+ 'x-mac-romanian' => 'x-mac-romanian',
+ 'x-mac-cyrillic' => 'x-mac-cyrillic',
+ 'x-mac-ukrainian' => 'x-mac-cyrillic',
+ 'x-mac-hebrew' => 'x-mac-hebrew',
+ 'x-mac-arabic' => 'x-mac-arabic',
+ 'x-mac-farsi' => 'x-mac-farsi',
+ 'x-mac-devanagari' => 'x-mac-devanagari',
+ 'x-mac-gujarati' => 'x-mac-gujarati',
+ 'x-mac-gurmukhi' => 'x-mac-gurmukhi',
+ 'armscii-8' => 'armscii-8',
+ 'x-viet-tcvn5712' => 'x-viet-tcvn5712',
+ 'x-viet-vps' => 'x-viet-vps',
+ 'iso-10646-ucs-2' => 'UTF-16BE',
+ 'x-iso-10646-ucs-2-be' => 'UTF-16BE',
+ 'x-iso-10646-ucs-2-le' => 'UTF-16LE',
+ 'x-user-defined' => 'x-user-defined',
+ 'x-johab' => 'x-johab',
+ 'latin1' => 'ISO-8859-1',
+ 'iso_8859-1' => 'ISO-8859-1',
+ 'iso8859-1' => 'ISO-8859-1',
+ 'iso8859-2' => 'ISO-8859-2',
+ 'iso8859-3' => 'ISO-8859-3',
+ 'iso8859-4' => 'ISO-8859-4',
+ 'iso8859-5' => 'ISO-8859-5',
+ 'iso8859-6' => 'ISO-8859-6',
+ 'iso8859-7' => 'ISO-8859-7',
+ 'iso8859-8' => 'ISO-8859-8',
+ 'iso8859-9' => 'ISO-8859-9',
+ 'iso8859-10' => 'ISO-8859-10',
+ 'iso8859-11' => 'ISO-8859-11',
+ 'iso8859-13' => 'ISO-8859-13',
+ 'iso8859-14' => 'ISO-8859-14',
+ 'iso8859-15' => 'ISO-8859-15',
+ 'iso_8859-1:1987' => 'ISO-8859-1',
+ 'iso-ir-100' => 'ISO-8859-1',
+ 'l1' => 'ISO-8859-1',
+ 'ibm819' => 'ISO-8859-1',
+ 'cp819' => 'ISO-8859-1',
+ 'csisolatin1' => 'ISO-8859-1',
+ 'latin2' => 'ISO-8859-2',
+ 'iso_8859-2' => 'ISO-8859-2',
+ 'iso_8859-2:1987' => 'ISO-8859-2',
+ 'iso-ir-101' => 'ISO-8859-2',
+ 'l2' => 'ISO-8859-2',
+ 'csisolatin2' => 'ISO-8859-2',
+ 'latin3' => 'ISO-8859-3',
+ 'iso_8859-3' => 'ISO-8859-3',
+ 'iso_8859-3:1988' => 'ISO-8859-3',
+ 'iso-ir-109' => 'ISO-8859-3',
+ 'l3' => 'ISO-8859-3',
+ 'csisolatin3' => 'ISO-8859-3',
+ 'latin4' => 'ISO-8859-4',
+ 'iso_8859-4' => 'ISO-8859-4',
+ 'iso_8859-4:1988' => 'ISO-8859-4',
+ 'iso-ir-110' => 'ISO-8859-4',
+ 'l4' => 'ISO-8859-4',
+ 'csisolatin4' => 'ISO-8859-4',
+ 'cyrillic' => 'ISO-8859-5',
+ 'iso_8859-5' => 'ISO-8859-5',
+ 'iso_8859-5:1988' => 'ISO-8859-5',
+ 'iso-ir-144' => 'ISO-8859-5',
+ 'csisolatincyrillic' => 'ISO-8859-5',
+ 'arabic' => 'ISO-8859-6',
+ 'iso_8859-6' => 'ISO-8859-6',
+ 'iso_8859-6:1987' => 'ISO-8859-6',
+ 'iso-ir-127' => 'ISO-8859-6',
+ 'ecma-114' => 'ISO-8859-6',
+ 'asmo-708' => 'ISO-8859-6',
+ 'csisolatinarabic' => 'ISO-8859-6',
+ 'csiso88596i' => 'ISO-8859-6-I',
+ 'csiso88596e' => 'ISO-8859-6-E',
+ 'greek' => 'ISO-8859-7',
+ 'greek8' => 'ISO-8859-7',
+ 'sun_eu_greek' => 'ISO-8859-7',
+ 'iso_8859-7' => 'ISO-8859-7',
+ 'iso_8859-7:1987' => 'ISO-8859-7',
+ 'iso-ir-126' => 'ISO-8859-7',
+ 'elot_928' => 'ISO-8859-7',
+ 'ecma-118' => 'ISO-8859-7',
+ 'csisolatingreek' => 'ISO-8859-7',
+ 'hebrew' => 'ISO-8859-8',
+ 'iso_8859-8' => 'ISO-8859-8',
+ 'visual' => 'ISO-8859-8',
+ 'iso_8859-8:1988' => 'ISO-8859-8',
+ 'iso-ir-138' => 'ISO-8859-8',
+ 'csisolatinhebrew' => 'ISO-8859-8',
+ 'csiso88598i' => 'ISO-8859-8',
+ 'iso-8859-8i' => 'ISO-8859-8',
+ 'logical' => 'ISO-8859-8',
+ 'csiso88598e' => 'ISO-8859-8-E',
+ 'latin5' => 'ISO-8859-9',
+ 'iso_8859-9' => 'ISO-8859-9',
+ 'iso_8859-9:1989' => 'ISO-8859-9',
+ 'iso-ir-148' => 'ISO-8859-9',
+ 'l5' => 'ISO-8859-9',
+ 'csisolatin5' => 'ISO-8859-9',
+ 'unicode-1-1-utf-8' => 'UTF-8',
+ 'utf8' => 'UTF-8',
+ 'x-sjis' => 'Shift_JIS',
+ 'shift-jis' => 'Shift_JIS',
+ 'ms_kanji' => 'Shift_JIS',
+ 'csshiftjis' => 'Shift_JIS',
+ 'windows-31j' => 'Shift_JIS',
+ 'cp932' => 'Shift_JIS',
+ 'sjis' => 'Shift_JIS',
+ 'cseucpkdfmtjapanese' => 'EUC-JP',
+ 'x-euc-jp' => 'EUC-JP',
+ 'csiso2022jp' => 'ISO-2022-JP',
+ 'iso-2022-jp-2' => 'ISO-2022-JP',
+ 'csiso2022jp2' => 'ISO-2022-JP',
+ 'csbig5' => 'Big5',
+ 'cn-big5' => 'Big5',
+ 'x-x-big5' => 'Big5',
+ 'zh_tw-big5' => 'Big5',
+ 'cseuckr' => 'EUC-KR',
+ 'ks_c_5601-1987' => 'EUC-KR',
+ 'iso-ir-149' => 'EUC-KR',
+ 'ks_c_5601-1989' => 'EUC-KR',
+ 'ksc_5601' => 'EUC-KR',
+ 'ksc5601' => 'EUC-KR',
+ 'korean' => 'EUC-KR',
+ 'csksc56011987' => 'EUC-KR',
+ '5601' => 'EUC-KR',
+ 'windows-949' => 'EUC-KR',
+ 'gb_2312-80' => 'GB2312',
+ 'iso-ir-58' => 'GB2312',
+ 'chinese' => 'GB2312',
+ 'csiso58gb231280' => 'GB2312',
+ 'csgb2312' => 'GB2312',
+ 'zh_cn.euc' => 'GB2312',
+ 'gb_2312' => 'GB2312',
+ 'x-cp1250' => 'windows-1250',
+ 'x-cp1251' => 'windows-1251',
+ 'x-cp1252' => 'windows-1252',
+ 'x-cp1253' => 'windows-1253',
+ 'x-cp1254' => 'windows-1254',
+ 'x-cp1255' => 'windows-1255',
+ 'x-cp1256' => 'windows-1256',
+ 'x-cp1257' => 'windows-1257',
+ 'x-cp1258' => 'windows-1258',
+ 'windows-874' => 'windows-874',
+ 'ibm874' => 'windows-874',
+ 'dos-874' => 'windows-874',
+ 'macintosh' => 'macintosh',
+ 'x-mac-roman' => 'macintosh',
+ 'mac' => 'macintosh',
+ 'csmacintosh' => 'macintosh',
+ 'cp866' => 'IBM866',
+ 'cp-866' => 'IBM866',
+ '866' => 'IBM866',
+ 'csibm866' => 'IBM866',
+ 'cp850' => 'IBM850',
+ '850' => 'IBM850',
+ 'csibm850' => 'IBM850',
+ 'cp852' => 'IBM852',
+ '852' => 'IBM852',
+ 'csibm852' => 'IBM852',
+ 'cp855' => 'IBM855',
+ '855' => 'IBM855',
+ 'csibm855' => 'IBM855',
+ 'cp857' => 'IBM857',
+ '857' => 'IBM857',
+ 'csibm857' => 'IBM857',
+ 'cp862' => 'IBM862',
+ '862' => 'IBM862',
+ 'csibm862' => 'IBM862',
+ 'cp864' => 'IBM864',
+ '864' => 'IBM864',
+ 'csibm864' => 'IBM864',
+ 'ibm-864' => 'IBM864',
+ 't.61' => 'T.61-8bit',
+ 'iso-ir-103' => 'T.61-8bit',
+ 'csiso103t618bit' => 'T.61-8bit',
+ 'x-unicode-2-0-utf-7' => 'UTF-7',
+ 'unicode-2-0-utf-7' => 'UTF-7',
+ 'unicode-1-1-utf-7' => 'UTF-7',
+ 'csunicode11utf7' => 'UTF-7',
+ 'csunicode' => 'UTF-16BE',
+ 'csunicode11' => 'UTF-16BE',
+ 'iso-10646-ucs-basic' => 'UTF-16BE',
+ 'csunicodeascii' => 'UTF-16BE',
+ 'iso-10646-unicode-latin1' => 'UTF-16BE',
+ 'csunicodelatin1' => 'UTF-16BE',
+ 'iso-10646' => 'UTF-16BE',
+ 'iso-10646-j-1' => 'UTF-16BE',
+ 'latin6' => 'ISO-8859-10',
+ 'iso-ir-157' => 'ISO-8859-10',
+ 'l6' => 'ISO-8859-10',
+ 'csisolatin6' => 'ISO-8859-10',
+ 'iso_8859-15' => 'ISO-8859-15',
+ 'csisolatin9' => 'ISO-8859-15',
+ 'l9' => 'ISO-8859-15',
+ 'ecma-cyrillic' => 'ISO-IR-111',
+ 'csiso111ecmacyrillic' => 'ISO-IR-111',
+ 'csiso2022kr' => 'ISO-2022-KR',
+ 'csviscii' => 'VISCII',
+ 'zh_tw-euc' => 'x-euc-tw',
+ 'iso88591' => 'ISO-8859-1',
+ 'iso88592' => 'ISO-8859-2',
+ 'iso88593' => 'ISO-8859-3',
+ 'iso88594' => 'ISO-8859-4',
+ 'iso88595' => 'ISO-8859-5',
+ 'iso88596' => 'ISO-8859-6',
+ 'iso88597' => 'ISO-8859-7',
+ 'iso88598' => 'ISO-8859-8',
+ 'iso88599' => 'ISO-8859-9',
+ 'iso885910' => 'ISO-8859-10',
+ 'iso885911' => 'ISO-8859-11',
+ 'iso885912' => 'ISO-8859-12',
+ 'iso885913' => 'ISO-8859-13',
+ 'iso885914' => 'ISO-8859-14',
+ 'iso885915' => 'ISO-8859-15',
+ 'tis620' => 'TIS-620',
+ 'cp1250' => 'windows-1250',
+ 'cp1251' => 'windows-1251',
+ 'cp1252' => 'windows-1252',
+ 'cp1253' => 'windows-1253',
+ 'cp1254' => 'windows-1254',
+ 'cp1255' => 'windows-1255',
+ 'cp1256' => 'windows-1256',
+ 'cp1257' => 'windows-1257',
+ 'cp1258' => 'windows-1258',
+ 'x-gbk' => 'gbk',
+ 'windows-936' => 'gbk',
+ 'ansi-1251' => 'windows-1251',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function decodeCharset($encodedString, $charset)
+ {
+ if (strtolower($charset) == 'utf-8' || strtolower($charset) == 'us-ascii') {
+ return $encodedString;
+ } else {
+ return iconv($this->getCharsetAlias($charset), 'UTF-8//TRANSLIT//IGNORE', $encodedString);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCharsetAlias($charset)
+ {
+ $charset = strtolower($charset);
+
+ if (array_key_exists($charset, $this->charsetAlias)) {
+ return $this->charsetAlias[$charset];
+ } else {
+ return null;
+ }
+ }
+}
--- /dev/null
+<?php namespace PhpMimeMailParser\Contracts;
+
+interface CharsetManager
+{
+
+ /**
+ * Decode the string from Charset
+ *
+ * @param string $encodedString The string in its original encoded state
+ * @param string $charset The Charset header of the part.
+ *
+ * @return string The decoded string
+ */
+ public function decodeCharset($encodedString, $charset);
+
+ /**
+ * Get charset alias
+ *
+ * @param string $charset .
+ *
+ * @return string The charset alias
+ */
+ public function getCharsetAlias($charset);
+}
--- /dev/null
+<?php
+
+namespace PhpMimeMailParser\Contracts;
+
+use PhpMimeMailParser\MimePart;
+use PhpMimeMailParser\MiddlewareStack;
+
+/**
+ * Process Mime parts by either:
+ * processing the part or calling the $next MiddlewareStack
+ */
+interface Middleware
+{
+ /**
+ * Process a mime part, optionally delegating parsing to the $next MiddlewareStack
+ *
+ * @param MimePart $part
+ * @param MiddlewareStack $next
+ *
+ * @return MimePart
+ */
+ public function parse(MimePart $part, MiddlewareStack $next);
+}
--- /dev/null
+<?php
+
+namespace PhpMimeMailParser;
+
+class Exception extends \RuntimeException
+{
+
+}
--- /dev/null
+<?php
+
+namespace PhpMimeMailParser;
+
+/**
+ * Wraps a callable as a Middleware
+ */
+class Middleware implements Contracts\Middleware
+{
+ /**
+ * Create a middleware using a callable $fn
+ *
+ * @param callable $fn
+ */
+ public function __construct(callable $fn)
+ {
+ $this->parser = $fn;
+ }
+
+ /**
+ * Process a mime part, optionally delegating parsing to the $next MiddlewareStack
+ */
+ public function parse(MimePart $part, MiddlewareStack $next)
+ {
+ return call_user_func($this->parser, $part, $next);
+ }
+}
--- /dev/null
+<?php
+
+namespace PhpMimeMailParser;
+
+use PhpMimeMailParser\Contracts\MiddleWare;
+
+/**
+ * A stack of middleware chained together by (MiddlewareStack $next)
+ */
+class MiddlewareStack
+{
+ /**
+ * Next MiddlewareStack in chain
+ *
+ * @var MiddlewareStack
+ */
+ protected $next;
+
+ /**
+ * Middleware in this MiddlewareStack
+ *
+ * @var Middleware
+ */
+ protected $middleware;
+
+ /**
+ * Construct the first middleware in this MiddlewareStack
+ * The next middleware is chained through $MiddlewareStack->add($Middleware)
+ *
+ * @param Middleware $middleware
+ */
+ public function __construct(Middleware $middleware = null)
+ {
+ $this->middleware = $middleware;
+ }
+
+ /**
+ * Creates a chained middleware in MiddlewareStack
+ *
+ * @param Middleware $middleware
+ * @return MiddlewareStack Immutable MiddlewareStack
+ */
+ public function add(Middleware $middleware)
+ {
+ $stack = new static($middleware);
+ $stack->next = $this;
+ return $stack;
+ }
+
+ /**
+ * Parses the MimePart by passing it through the Middleware
+ * @param MimePart $part
+ * @return MimePart
+ */
+ public function parse(MimePart $part)
+ {
+ if (!$this->middleware) {
+ return $part;
+ }
+ $part = call_user_func(array($this->middleware, 'parse'), $part, $this->next);
+ return $part;
+ }
+
+ /**
+ * Creates a MiddlewareStack based on an array of middleware
+ *
+ * @param Middleware[] $middlewares
+ * @return MiddlewareStack
+ */
+ public static function factory(array $middlewares = array())
+ {
+ $stack = new static;
+ foreach ($middlewares as $middleware) {
+ $stack = $stack->add($middleware);
+ }
+ return $stack;
+ }
+
+ /**
+ * Allow calling MiddlewareStack instance directly to invoke parse()
+ *
+ * @param MimePart $part
+ * @return MimePart
+ */
+ public function __invoke(MimePart $part)
+ {
+ return $this->parse($part);
+ }
+}
--- /dev/null
+<?php
+
+namespace PhpMimeMailParser;
+
+/**
+ * Mime Part
+ * Represents the results of mailparse_msg_get_part_data()
+ *
+ * Note ArrayAccess::offsetSet() cannot modify deeply nestated arrays.
+ * When modifying use getPart() and setPart() for deep nested data modification
+ *
+ * @example
+ *
+ * $MimePart['headers']['from'] = 'modified@example.com' // fails
+ *
+ * // correct
+ * $part = $MimePart->getPart();
+ * $part['headers']['from'] = 'modified@example.com';
+ * $MimePart->setPart($part);
+ */
+class MimePart implements \ArrayAccess
+{
+ /**
+ * Internal mime part
+ *
+ * @var array
+ */
+ protected $part = array();
+
+ /**
+ * Immutable Part Id
+ *
+ * @var string
+ */
+ private $id;
+
+ /**
+ * Create a mime part
+ *
+ * @param array $part
+ * @param string $id
+ */
+ public function __construct($id, array $part)
+ {
+ $this->part = $part;
+ $this->id = $id;
+ }
+
+ /**
+ * Retrieve the part Id
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * Retrieve the part data
+ *
+ * @return array
+ */
+ public function getPart()
+ {
+ return $this->part;
+ }
+
+ /**
+ * Set the mime part data
+ *
+ * @param array $part
+ * @return void
+ */
+ public function setPart(array $part)
+ {
+ $this->part = $part;
+ }
+
+ /**
+ * ArrayAccess
+ */
+ public function offsetSet($offset, $value)
+ {
+ if (is_null($offset)) {
+ $this->part[] = $value;
+ } else {
+ $this->part[$offset] = $value;
+ }
+ }
+
+ /**
+ * ArrayAccess
+ */
+ public function offsetExists($offset)
+ {
+ return isset($this->part[$offset]);
+ }
+
+ /**
+ * ArrayAccess
+ */
+ public function offsetUnset($offset)
+ {
+ unset($this->part[$offset]);
+ }
+
+ /**
+ * ArrayAccess
+ */
+ public function offsetGet($offset)
+ {
+ return isset($this->part[$offset]) ? $this->part[$offset] : null;
+ }
+}
--- /dev/null
+<?php
+
+namespace PhpMimeMailParser;
+
+use PhpMimeMailParser\Contracts\CharsetManager;
+
+/**
+ * Parser of php-mime-mail-parser
+ *
+ * Fully Tested Mailparse Extension Wrapper for PHP 5.4+
+ *
+ */
+class Parser
+{
+ /**
+ * Attachment filename argument option for ->saveAttachments().
+ */
+ const ATTACHMENT_DUPLICATE_THROW = 'DuplicateThrow';
+ const ATTACHMENT_DUPLICATE_SUFFIX = 'DuplicateSuffix';
+ const ATTACHMENT_RANDOM_FILENAME = 'RandomFilename';
+
+ /**
+ * PHP MimeParser Resource ID
+ *
+ * @var resource $resource
+ */
+ protected $resource;
+
+ /**
+ * A file pointer to email
+ *
+ * @var resource $stream
+ */
+ protected $stream;
+
+ /**
+ * A text of an email
+ *
+ * @var string $data
+ */
+ protected $data;
+
+ /**
+ * Parts of an email
+ *
+ * @var array $parts
+ */
+ protected $parts;
+
+ /**
+ * @var CharsetManager object
+ */
+ protected $charset;
+
+ /**
+ * Valid stream modes for reading
+ *
+ * @var array
+ */
+ protected static $readableModes = [
+ 'r', 'r+', 'w+', 'a+', 'x+', 'c+', 'rb', 'r+b', 'w+b', 'a+b',
+ 'x+b', 'c+b', 'rt', 'r+t', 'w+t', 'a+t', 'x+t', 'c+t'
+ ];
+
+ /**
+ * Stack of middleware registered to process data
+ *
+ * @var MiddlewareStack
+ */
+ protected $middlewareStack;
+
+ /**
+ * Parser constructor.
+ *
+ * @param CharsetManager|null $charset
+ */
+ public function __construct(CharsetManager $charset = null)
+ {
+ if ($charset == null) {
+ $charset = new Charset();
+ }
+
+ $this->charset = $charset;
+ $this->middlewareStack = new MiddlewareStack();
+ }
+
+ /**
+ * Free the held resources
+ *
+ * @return void
+ */
+ public function __destruct()
+ {
+ // clear the email file resource
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ // clear the MailParse resource
+ if (is_resource($this->resource)) {
+ mailparse_msg_free($this->resource);
+ }
+ }
+
+ /**
+ * Set the file path we use to get the email text
+ *
+ * @param string $path File path to the MIME mail
+ *
+ * @return Parser MimeMailParser Instance
+ */
+ public function setPath($path)
+ {
+ // should parse message incrementally from file
+ $this->resource = mailparse_msg_parse_file($path);
+ $this->stream = fopen($path, 'r');
+ $this->parse();
+
+ return $this;
+ }
+
+ /**
+ * Set the Stream resource we use to get the email text
+ *
+ * @param resource $stream
+ *
+ * @return Parser MimeMailParser Instance
+ * @throws Exception
+ */
+ public function setStream($stream)
+ {
+ // streams have to be cached to file first
+ $meta = @stream_get_meta_data($stream);
+ if (!$meta || !$meta['mode'] || !in_array($meta['mode'], self::$readableModes, true) || $meta['eof']) {
+ throw new Exception(
+ 'setStream() expects parameter stream to be readable stream resource.'
+ );
+ }
+
+ /** @var resource $tmp_fp */
+ $tmp_fp = tmpfile();
+ if ($tmp_fp) {
+ while (!feof($stream)) {
+ fwrite($tmp_fp, fread($stream, 2028));
+ }
+ fseek($tmp_fp, 0);
+ $this->stream = &$tmp_fp;
+ } else {
+ throw new Exception(
+ 'Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'
+ );
+ }
+ fclose($stream);
+
+ $this->resource = mailparse_msg_create();
+ // parses the message incrementally (low memory usage but slower)
+ while (!feof($this->stream)) {
+ mailparse_msg_parse($this->resource, fread($this->stream, 2082));
+ }
+ $this->parse();
+
+ return $this;
+ }
+
+ /**
+ * Set the email text
+ *
+ * @param string $data
+ *
+ * @return Parser MimeMailParser Instance
+ */
+ public function setText($data)
+ {
+ if (!$data) {
+ throw new Exception('You must not call MimeMailParser::setText with an empty string parameter');
+ }
+ $this->resource = mailparse_msg_create();
+ // does not parse incrementally, fast memory hog might explode
+ mailparse_msg_parse($this->resource, $data);
+ $this->data = $data;
+ $this->parse();
+
+ return $this;
+ }
+
+ /**
+ * Parse the Message into parts
+ *
+ * @return void
+ */
+ protected function parse()
+ {
+ $structure = mailparse_msg_get_structure($this->resource);
+ $this->parts = [];
+ foreach ($structure as $part_id) {
+ $part = mailparse_msg_get_part($this->resource, $part_id);
+ $part_data = mailparse_msg_get_part_data($part);
+ $mimePart = new MimePart($part_id, $part_data);
+ // let each middleware parse the part before saving
+ $this->parts[$part_id] = $this->middlewareStack->parse($mimePart)->getPart();
+ }
+ }
+
+ /**
+ * Retrieve a specific Email Header, without charset conversion.
+ *
+ * @param string $name Header name (case-insensitive)
+ *
+ * @return string
+ * @throws Exception
+ */
+ public function getRawHeader($name)
+ {
+ $name = strtolower($name);
+ if (isset($this->parts[1])) {
+ $headers = $this->getPart('headers', $this->parts[1]);
+
+ return (isset($headers[$name])) ? $headers[$name] : false;
+ } else {
+ throw new Exception(
+ 'setPath() or setText() or setStream() must be called before retrieving email headers.'
+ );
+ }
+ }
+
+ /**
+ * Retrieve a specific Email Header
+ *
+ * @param string $name Header name (case-insensitive)
+ *
+ * @return string
+ */
+ public function getHeader($name)
+ {
+ $rawHeader = $this->getRawHeader($name);
+ if ($rawHeader === false) {
+ return false;
+ }
+
+ return $this->decodeHeader($rawHeader);
+ }
+
+ /**
+ * Retrieve all mail headers
+ *
+ * @return array
+ * @throws Exception
+ */
+ public function getHeaders()
+ {
+ if (isset($this->parts[1])) {
+ $headers = $this->getPart('headers', $this->parts[1]);
+ foreach ($headers as $name => &$value) {
+ if (is_array($value)) {
+ foreach ($value as &$v) {
+ $v = $this->decodeSingleHeader($v);
+ }
+ } else {
+ $value = $this->decodeSingleHeader($value);
+ }
+ }
+
+ return $headers;
+ } else {
+ throw new Exception(
+ 'setPath() or setText() or setStream() must be called before retrieving email headers.'
+ );
+ }
+ }
+
+ /**
+ * Retrieve the raw mail headers as a string
+ *
+ * @return string
+ * @throws Exception
+ */
+ public function getHeadersRaw()
+ {
+ if (isset($this->parts[1])) {
+ return $this->getPartHeader($this->parts[1]);
+ } else {
+ throw new Exception(
+ 'setPath() or setText() or setStream() must be called before retrieving email headers.'
+ );
+ }
+ }
+
+ /**
+ * Retrieve the raw Header of a MIME part
+ *
+ * @return String
+ * @param $part Object
+ * @throws Exception
+ */
+ protected function getPartHeader(&$part)
+ {
+ $header = '';
+ if ($this->stream) {
+ $header = $this->getPartHeaderFromFile($part);
+ } elseif ($this->data) {
+ $header = $this->getPartHeaderFromText($part);
+ }
+ return $header;
+ }
+
+ /**
+ * Retrieve the Header from a MIME part from file
+ *
+ * @return String Mime Header Part
+ * @param $part Array
+ */
+ protected function getPartHeaderFromFile(&$part)
+ {
+ $start = $part['starting-pos'];
+ $end = $part['starting-pos-body'];
+ fseek($this->stream, $start, SEEK_SET);
+ $header = fread($this->stream, $end - $start);
+ return $header;
+ }
+
+ /**
+ * Retrieve the Header from a MIME part from text
+ *
+ * @return String Mime Header Part
+ * @param $part Array
+ */
+ protected function getPartHeaderFromText(&$part)
+ {
+ $start = $part['starting-pos'];
+ $end = $part['starting-pos-body'];
+ $header = substr($this->data, $start, $end - $start);
+ return $header;
+ }
+
+ /**
+ * Checks whether a given part ID is a child of another part
+ * eg. an RFC822 attachment may have one or more text parts
+ *
+ * @param string $partId
+ * @param string $parentPartId
+ * @return bool
+ */
+ protected function partIdIsChildOfPart($partId, $parentPartId)
+ {
+ $parentPartId = $parentPartId.'.';
+ return substr($partId, 0, strlen($parentPartId)) == $parentPartId;
+ }
+
+ /**
+ * Whether the given part ID is a child of any attachment part in the message.
+ *
+ * @param string $checkPartId
+ * @return bool
+ */
+ protected function partIdIsChildOfAnAttachment($checkPartId)
+ {
+ foreach ($this->parts as $partId => $part) {
+ if ($this->getPart('content-disposition', $part) == 'attachment') {
+ if ($this->partIdIsChildOfPart($checkPartId, $partId)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the email message body in the specified format
+ *
+ * @param string $type text, html or htmlEmbedded
+ *
+ * @return string Body
+ * @throws Exception
+ */
+ public function getMessageBody($type = 'text')
+ {
+ $mime_types = [
+ 'text' => 'text/plain',
+ 'html' => 'text/html',
+ 'htmlEmbedded' => 'text/html',
+ ];
+
+ if (in_array($type, array_keys($mime_types))) {
+ $part_type = $type === 'htmlEmbedded' ? 'html' : $type;
+ $inline_parts = $this->getInlineParts($part_type);
+ $body = empty($inline_parts) ? '' : $inline_parts[0];
+ } else {
+ throw new Exception(
+ 'Invalid type specified for getMessageBody(). Expected: text, html or htmlEmbeded.'
+ );
+ }
+
+ if ($type == 'htmlEmbedded') {
+ $attachments = $this->getAttachments();
+ foreach ($attachments as $attachment) {
+ if ($attachment->getContentID() != '') {
+ $body = str_replace(
+ '"cid:'.$attachment->getContentID().'"',
+ '"'.$this->getEmbeddedData($attachment->getContentID()).'"',
+ $body
+ );
+ }
+ }
+ }
+
+ return $body;
+ }
+
+ /**
+ * Returns the embedded data structure
+ *
+ * @param string $contentId Content-Id
+ *
+ * @return string
+ */
+ protected function getEmbeddedData($contentId)
+ {
+ foreach ($this->parts as $part) {
+ if ($this->getPart('content-id', $part) == $contentId) {
+ $embeddedData = 'data:';
+ $embeddedData .= $this->getPart('content-type', $part);
+ $embeddedData .= ';'.$this->getPart('transfer-encoding', $part);
+ $embeddedData .= ','.$this->getPartBody($part);
+ return $embeddedData;
+ }
+ }
+ return '';
+ }
+
+ /**
+ * Return an array with the following keys display, address, is_group
+ *
+ * @param string $name Header name (case-insensitive)
+ *
+ * @return array
+ */
+ public function getAddresses($name)
+ {
+ $value = $this->getRawHeader($name);
+ $value = (is_array($value)) ? $value[0] : $value;
+ $addresses = mailparse_rfc822_parse_addresses($value);
+ foreach ($addresses as $i => $item) {
+ $addresses[$i]['display'] = $this->decodeHeader($item['display']);
+ }
+ return $addresses;
+ }
+
+ /**
+ * Returns the attachments contents in order of appearance
+ *
+ * @return Attachment[]
+ */
+ public function getInlineParts($type = 'text')
+ {
+ $inline_parts = [];
+ $mime_types = [
+ 'text' => 'text/plain',
+ 'html' => 'text/html',
+ ];
+
+ if (!in_array($type, array_keys($mime_types))) {
+ throw new Exception('Invalid type specified for getInlineParts(). "type" can either be text or html.');
+ }
+
+ foreach ($this->parts as $partId => $part) {
+ if ($this->getPart('content-type', $part) == $mime_types[$type]
+ && $this->getPart('content-disposition', $part) != 'attachment'
+ && !$this->partIdIsChildOfAnAttachment($partId)
+ ) {
+ $headers = $this->getPart('headers', $part);
+ $encodingType = array_key_exists('content-transfer-encoding', $headers) ?
+ $headers['content-transfer-encoding'] : '';
+ $undecoded_body = $this->decodeContentTransfer($this->getPartBody($part), $encodingType);
+ $inline_parts[] = $this->charset->decodeCharset($undecoded_body, $this->getPartCharset($part));
+ }
+ }
+
+ return $inline_parts;
+ }
+
+ /**
+ * Returns the attachments contents in order of appearance
+ *
+ * @return Attachment[]
+ */
+ public function getAttachments($include_inline = true)
+ {
+ $attachments = [];
+ $dispositions = $include_inline ? ['attachment', 'inline'] : ['attachment'];
+ $non_attachment_types = ['text/plain', 'text/html'];
+ $nonameIter = 0;
+
+ foreach ($this->parts as $part) {
+ $disposition = $this->getPart('content-disposition', $part);
+ $filename = 'noname';
+
+ if (isset($part['disposition-filename'])) {
+ $filename = $this->decodeHeader($part['disposition-filename']);
+ // Escape all potentially unsafe characters from the filename
+ $filename = preg_replace('((^\.)|\/|(\.$))', '_', $filename);
+ } elseif (isset($part['content-name'])) {
+ // if we have no disposition but we have a content-name, it's a valid attachment.
+ // we simulate the presence of an attachment disposition with a disposition filename
+ $filename = $this->decodeHeader($part['content-name']);
+ // Escape all potentially unsafe characters from the filename
+ $filename = preg_replace('((^\.)|\/|(\.$))', '_', $filename);
+ $disposition = 'attachment';
+ } elseif (in_array($part['content-type'], $non_attachment_types, true)
+ && $disposition !== 'attachment') {
+ // it is a message body, no attachment
+ continue;
+ } elseif (substr($part['content-type'], 0, 10) !== 'multipart/') {
+ // if we cannot get it by getMessageBody(), we assume it is an attachment
+ $disposition = 'attachment';
+ }
+ if (in_array($disposition, ['attachment', 'inline']) === false && !empty($disposition)) {
+ $disposition = 'attachment';
+ }
+
+ if (in_array($disposition, $dispositions) === true) {
+ if ($filename == 'noname') {
+ $nonameIter++;
+ $filename = 'noname'.$nonameIter;
+ }
+
+ $headersAttachments = $this->getPart('headers', $part);
+ $contentidAttachments = $this->getPart('content-id', $part);
+
+ $attachmentStream = $this->getAttachmentStream($part);
+ $mimePartStr = $this->getPartComplete($part);
+
+ $attachments[] = new Attachment(
+ $filename,
+ $this->getPart('content-type', $part),
+ $attachmentStream,
+ $disposition,
+ $contentidAttachments,
+ $headersAttachments,
+ $mimePartStr
+ );
+ }
+ }
+
+ return $attachments;
+ }
+
+ /**
+ * Save attachments in a folder
+ *
+ * @param string $attach_dir directory
+ * @param bool $include_inline
+ * @param string $filenameStrategy How to generate attachment filenames
+ *
+ * @return array Saved attachments paths
+ * @throws Exception
+ */
+ public function saveAttachments(
+ $attach_dir,
+ $include_inline = true,
+ $filenameStrategy = self::ATTACHMENT_DUPLICATE_SUFFIX
+ ) {
+ $attachments = $this->getAttachments($include_inline);
+ if (empty($attachments)) {
+ return false;
+ }
+
+ if (!is_dir($attach_dir)) {
+ mkdir($attach_dir);
+ }
+
+ $attachments_paths = [];
+ foreach ($attachments as $attachment) {
+ // Determine filename
+ switch ($filenameStrategy) {
+ case self::ATTACHMENT_RANDOM_FILENAME:
+ $attachment_path = tempnam($attach_dir, '');
+ break;
+ case self::ATTACHMENT_DUPLICATE_THROW:
+ case self::ATTACHMENT_DUPLICATE_SUFFIX:
+ $attachment_path = $attach_dir.$attachment->getFilename();
+ break;
+ default:
+ throw new Exception('Invalid filename strategy argument provided.');
+ }
+
+ // Handle duplicate filename
+ if (file_exists($attachment_path)) {
+ switch ($filenameStrategy) {
+ case self::ATTACHMENT_DUPLICATE_THROW:
+ throw new Exception('Could not create file for attachment: duplicate filename.');
+ case self::ATTACHMENT_DUPLICATE_SUFFIX:
+ $attachment_path = tempnam($attach_dir, $attachment->getFilename());
+ break;
+ }
+ }
+
+ /** @var resource $fp */
+ if ($fp = fopen($attachment_path, 'w')) {
+ while ($bytes = $attachment->read()) {
+ fwrite($fp, $bytes);
+ }
+ fclose($fp);
+ $attachments_paths[] = realpath($attachment_path);
+ } else {
+ throw new Exception('Could not write attachments. Your directory may be unwritable by PHP.');
+ }
+ }
+
+ return $attachments_paths;
+ }
+
+ /**
+ * Read the attachment Body and save temporary file resource
+ *
+ * @param array $part
+ *
+ * @return resource Mime Body Part
+ * @throws Exception
+ */
+ protected function getAttachmentStream(&$part)
+ {
+ /** @var resource $temp_fp */
+ $temp_fp = tmpfile();
+
+ $headers = $this->getPart('headers', $part);
+ $encodingType = array_key_exists('content-transfer-encoding', $headers) ?
+ $headers['content-transfer-encoding'] : '';
+
+ if ($temp_fp) {
+ if ($this->stream) {
+ $start = $part['starting-pos-body'];
+ $end = $part['ending-pos-body'];
+ fseek($this->stream, $start, SEEK_SET);
+ $len = $end - $start;
+ $written = 0;
+ while ($written < $len) {
+ $write = $len;
+ $data = fread($this->stream, $write);
+ fwrite($temp_fp, $this->decodeContentTransfer($data, $encodingType));
+ $written += $write;
+ }
+ } elseif ($this->data) {
+ $attachment = $this->decodeContentTransfer($this->getPartBodyFromText($part), $encodingType);
+ fwrite($temp_fp, $attachment, strlen($attachment));
+ }
+ fseek($temp_fp, 0, SEEK_SET);
+ } else {
+ throw new Exception(
+ 'Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'
+ );
+ }
+
+ return $temp_fp;
+ }
+
+ /**
+ * Decode the string from Content-Transfer-Encoding
+ *
+ * @param string $encodedString The string in its original encoded state
+ * @param string $encodingType The encoding type from the Content-Transfer-Encoding header of the part.
+ *
+ * @return string The decoded string
+ */
+ protected function decodeContentTransfer($encodedString, $encodingType)
+ {
+ if (is_array($encodingType)) {
+ $encodingType = $encodingType[0];
+ }
+
+ $encodingType = strtolower($encodingType);
+ if ($encodingType == 'base64') {
+ return base64_decode($encodedString);
+ } elseif ($encodingType == 'quoted-printable') {
+ return quoted_printable_decode($encodedString);
+ } else {
+ return $encodedString;
+ }
+ }
+
+ /**
+ * $input can be a string or array
+ *
+ * @param string|array $input
+ *
+ * @return string
+ */
+ protected function decodeHeader($input)
+ {
+ //Sometimes we have 2 label From so we take only the first
+ if (is_array($input)) {
+ return $this->decodeSingleHeader($input[0]);
+ }
+
+ return $this->decodeSingleHeader($input);
+ }
+
+ /**
+ * Decodes a single header (= string)
+ *
+ * @param string $input
+ *
+ * @return string
+ */
+ protected function decodeSingleHeader($input)
+ {
+ // For each encoded-word...
+ while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)((\s+)=\?)?/i', $input, $matches)) {
+ $encoded = $matches[1];
+ $charset = $matches[2];
+ $encoding = $matches[3];
+ $text = $matches[4];
+ $space = isset($matches[6]) ? $matches[6] : '';
+
+ switch (strtolower($encoding)) {
+ case 'b':
+ $text = $this->decodeContentTransfer($text, 'base64');
+ break;
+
+ case 'q':
+ $text = str_replace('_', ' ', $text);
+ preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
+ foreach ($matches[1] as $value) {
+ $text = str_replace('='.$value, chr(hexdec($value)), $text);
+ }
+ break;
+ }
+
+ $text = $this->charset->decodeCharset($text, $this->charset->getCharsetAlias($charset));
+ $input = str_replace($encoded.$space, $text, $input);
+ }
+
+ return $input;
+ }
+
+ /**
+ * Return the charset of the MIME part
+ *
+ * @param array $part
+ *
+ * @return string
+ */
+ protected function getPartCharset($part)
+ {
+ if (isset($part['charset'])) {
+ return $this->charset->getCharsetAlias($part['charset']);
+ } else {
+ return 'us-ascii';
+ }
+ }
+
+ /**
+ * Retrieve a specified MIME part
+ *
+ * @param string $type
+ * @param array $parts
+ *
+ * @return string|array
+ */
+ protected function getPart($type, $parts)
+ {
+ return (isset($parts[$type])) ? $parts[$type] : false;
+ }
+
+ /**
+ * Retrieve the Body of a MIME part
+ *
+ * @param array $part
+ *
+ * @return string
+ */
+ protected function getPartBody(&$part)
+ {
+ $body = '';
+ if ($this->stream) {
+ $body = $this->getPartBodyFromFile($part);
+ } elseif ($this->data) {
+ $body = $this->getPartBodyFromText($part);
+ }
+
+ return $body;
+ }
+
+ /**
+ * Retrieve the Body from a MIME part from file
+ *
+ * @param array $part
+ *
+ * @return string Mime Body Part
+ */
+ protected function getPartBodyFromFile(&$part)
+ {
+ $start = $part['starting-pos-body'];
+ $end = $part['ending-pos-body'];
+ $body = '';
+ if ($end - $start > 0) {
+ fseek($this->stream, $start, SEEK_SET);
+ $body = fread($this->stream, $end - $start);
+ }
+
+ return $body;
+ }
+
+ /**
+ * Retrieve the Body from a MIME part from text
+ *
+ * @param array $part
+ *
+ * @return string Mime Body Part
+ */
+ protected function getPartBodyFromText(&$part)
+ {
+ $start = $part['starting-pos-body'];
+ $end = $part['ending-pos-body'];
+
+ return substr($this->data, $start, $end - $start);
+ }
+
+ /**
+ * Retrieve the content of a MIME part
+ *
+ * @param array $part
+ *
+ * @return string
+ */
+ protected function getPartComplete(&$part)
+ {
+ $body = '';
+ if ($this->stream) {
+ $body = $this->getPartFromFile($part);
+ } elseif ($this->data) {
+ $body = $this->getPartFromText($part);
+ }
+
+ return $body;
+ }
+
+ /**
+ * Retrieve the content from a MIME part from file
+ *
+ * @param array $part
+ *
+ * @return string Mime Content
+ */
+ protected function getPartFromFile(&$part)
+ {
+ $start = $part['starting-pos'];
+ $end = $part['ending-pos'];
+ $body = '';
+ if ($end - $start > 0) {
+ fseek($this->stream, $start, SEEK_SET);
+ $body = fread($this->stream, $end - $start);
+ }
+
+ return $body;
+ }
+
+ /**
+ * Retrieve the content from a MIME part from text
+ *
+ * @param array $part
+ *
+ * @return string Mime Content
+ */
+ protected function getPartFromText(&$part)
+ {
+ $start = $part['starting-pos'];
+ $end = $part['ending-pos'];
+
+ return substr($this->data, $start, $end - $start);
+ }
+
+ /**
+ * Retrieve the resource
+ *
+ * @return resource resource
+ */
+ public function getResource()
+ {
+ return $this->resource;
+ }
+
+ /**
+ * Retrieve the file pointer to email
+ *
+ * @return resource stream
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+
+ /**
+ * Retrieve the text of an email
+ *
+ * @return string data
+ */
+ public function getData()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Retrieve the parts of an email
+ *
+ * @return array parts
+ */
+ public function getParts()
+ {
+ return $this->parts;
+ }
+
+ /**
+ * Retrieve the charset manager object
+ *
+ * @return CharsetManager charset
+ */
+ public function getCharset()
+ {
+ return $this->charset;
+ }
+
+ /**
+ * Add a middleware to the parser MiddlewareStack
+ * Each middleware is invoked when:
+ * a MimePart is retrieved by mailparse_msg_get_part_data() during $this->parse()
+ * The middleware will receive MimePart $part and the next MiddlewareStack $next
+ *
+ * Eg:
+ *
+ * $Parser->addMiddleware(function(MimePart $part, MiddlewareStack $next) {
+ * // do something with the $part
+ * return $next($part);
+ * });
+ *
+ * @param callable $middleware Plain Function or Middleware Instance to execute
+ * @return void
+ */
+ public function addMiddleware(callable $middleware)
+ {
+ if (!$middleware instanceof Middleware) {
+ $middleware = new Middleware($middleware);
+ }
+ $this->middlewareStack = $this->middlewareStack->add($middleware);
+ }
+}