Attachment.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. /*
  3. * File: Attachment.php
  4. * Category: -
  5. * Author: M. Goldenbaum
  6. * Created: 16.03.18 19:37
  7. * Updated: -
  8. *
  9. * Description:
  10. * -
  11. */
  12. namespace Webklex\PHPIMAP;
  13. use Illuminate\Support\Str;
  14. use Webklex\PHPIMAP\Exceptions\MaskNotFoundException;
  15. use Webklex\PHPIMAP\Exceptions\MethodNotFoundException;
  16. use Webklex\PHPIMAP\Support\Masks\AttachmentMask;
  17. /**
  18. * Class Attachment
  19. *
  20. * @package Webklex\PHPIMAP
  21. *
  22. * @property integer part_number
  23. * @property integer size
  24. * @property string content
  25. * @property string type
  26. * @property string content_type
  27. * @property string id
  28. * @property string name
  29. * @property string disposition
  30. * @property string img_src
  31. *
  32. * @method integer getPartNumber()
  33. * @method integer setPartNumber(integer $part_number)
  34. * @method string getContent()
  35. * @method string setContent(string $content)
  36. * @method string getType()
  37. * @method string setType(string $type)
  38. * @method string getContentType()
  39. * @method string setContentType(string $content_type)
  40. * @method string getId()
  41. * @method string setId(string $id)
  42. * @method string getSize()
  43. * @method string setSize(integer $size)
  44. * @method string getName()
  45. * @method string getDisposition()
  46. * @method string setDisposition(string $disposition)
  47. * @method string setImgSrc(string $img_src)
  48. */
  49. class Attachment {
  50. /**
  51. * @var Message $oMessage
  52. */
  53. protected $oMessage;
  54. /**
  55. * Used config
  56. *
  57. * @var array $config
  58. */
  59. protected $config = [];
  60. /** @var Part $part */
  61. protected $part;
  62. /**
  63. * Attribute holder
  64. *
  65. * @var array $attributes
  66. */
  67. protected $attributes = [
  68. 'content' => null,
  69. 'type' => null,
  70. 'part_number' => 0,
  71. 'content_type' => null,
  72. 'id' => null,
  73. 'name' => null,
  74. 'disposition' => null,
  75. 'img_src' => null,
  76. 'size' => null,
  77. ];
  78. /**
  79. * Default mask
  80. *
  81. * @var string $mask
  82. */
  83. protected $mask = AttachmentMask::class;
  84. /**
  85. * Attachment constructor.
  86. * @param Message $oMessage
  87. * @param Part $part
  88. */
  89. public function __construct(Message $oMessage, Part $part) {
  90. $this->config = ClientManager::get('options');
  91. $this->oMessage = $oMessage;
  92. $this->part = $part;
  93. $this->part_number = $part->part_number;
  94. $default_mask = $this->oMessage->getClient()->getDefaultAttachmentMask();
  95. if($default_mask != null) {
  96. $this->mask = $default_mask;
  97. }
  98. $this->findType();
  99. $this->fetch();
  100. }
  101. /**
  102. * Call dynamic attribute setter and getter methods
  103. * @param string $method
  104. * @param array $arguments
  105. *
  106. * @return mixed
  107. * @throws MethodNotFoundException
  108. */
  109. public function __call($method, $arguments) {
  110. if(strtolower(substr($method, 0, 3)) === 'get') {
  111. $name = Str::snake(substr($method, 3));
  112. if(isset($this->attributes[$name])) {
  113. return $this->attributes[$name];
  114. }
  115. return null;
  116. }elseif (strtolower(substr($method, 0, 3)) === 'set') {
  117. $name = Str::snake(substr($method, 3));
  118. $this->attributes[$name] = array_pop($arguments);
  119. return $this->attributes[$name];
  120. }
  121. throw new MethodNotFoundException("Method ".self::class.'::'.$method.'() is not supported');
  122. }
  123. /**
  124. * Magic setter
  125. * @param $name
  126. * @param $value
  127. *
  128. * @return mixed
  129. */
  130. public function __set($name, $value) {
  131. $this->attributes[$name] = $value;
  132. return $this->attributes[$name];
  133. }
  134. /**
  135. * magic getter
  136. * @param $name
  137. *
  138. * @return mixed|null
  139. */
  140. public function __get($name) {
  141. if(isset($this->attributes[$name])) {
  142. return $this->attributes[$name];
  143. }
  144. return null;
  145. }
  146. /**
  147. * Determine the structure type
  148. */
  149. protected function findType() {
  150. switch ($this->part->type) {
  151. case IMAP::ATTACHMENT_TYPE_MESSAGE:
  152. $this->type = 'message';
  153. break;
  154. case IMAP::ATTACHMENT_TYPE_APPLICATION:
  155. $this->type = 'application';
  156. break;
  157. case IMAP::ATTACHMENT_TYPE_AUDIO:
  158. $this->type = 'audio';
  159. break;
  160. case IMAP::ATTACHMENT_TYPE_IMAGE:
  161. $this->type = 'image';
  162. break;
  163. case IMAP::ATTACHMENT_TYPE_VIDEO:
  164. $this->type = 'video';
  165. break;
  166. case IMAP::ATTACHMENT_TYPE_MODEL:
  167. $this->type = 'model';
  168. break;
  169. case IMAP::ATTACHMENT_TYPE_TEXT:
  170. $this->type = 'text';
  171. break;
  172. case IMAP::ATTACHMENT_TYPE_MULTIPART:
  173. $this->type = 'multipart';
  174. break;
  175. default:
  176. $this->type = 'other';
  177. break;
  178. }
  179. }
  180. /**
  181. * Fetch the given attachment
  182. */
  183. protected function fetch() {
  184. $content = $this->part->content;
  185. $this->content_type = $this->part->content_type;
  186. $this->content = $this->oMessage->decodeString($content, $this->part->encoding);
  187. if (($id = $this->part->id) !== null) {
  188. $this->id = str_replace(['<', '>'], '', $id);
  189. }
  190. $this->size = $this->part->bytes;
  191. $this->disposition = $this->part->disposition;
  192. if (($filename = $this->part->filename) !== null) {
  193. $this->setName($filename);
  194. } elseif (($name = $this->part->name) !== null) {
  195. $this->setName($name);
  196. }else {
  197. $this->setName("undefined");
  198. }
  199. if (IMAP::ATTACHMENT_TYPE_MESSAGE == $this->part->type) {
  200. if ($this->part->ifdescription) {
  201. $this->setName($this->part->description);
  202. } else {
  203. $this->setName($this->part->subtype);
  204. }
  205. }
  206. }
  207. /**
  208. * Save the attachment content to your filesystem
  209. * @param string $path
  210. * @param string|null $filename
  211. *
  212. * @return boolean
  213. */
  214. public function save($path, $filename = null) {
  215. $filename = $filename ? $filename : $this->getName();
  216. return file_put_contents($path.$filename, $this->getContent()) !== false;
  217. }
  218. /**
  219. * Set the attachment name and try to decode it
  220. * @param $name
  221. */
  222. public function setName($name) {
  223. $decoder = $this->config['decoder']['attachment'];
  224. if ($name !== null) {
  225. if($decoder === 'utf-8' && extension_loaded('imap')) {
  226. $this->name = \imap_utf8($name);
  227. }else{
  228. $this->name = mb_decode_mimeheader($name);
  229. }
  230. }
  231. }
  232. /**
  233. * Get the attachment mime type
  234. *
  235. * @return string|null
  236. */
  237. public function getMimeType(){
  238. return (new \finfo())->buffer($this->getContent(), FILEINFO_MIME_TYPE);
  239. }
  240. /**
  241. * Try to guess the attachment file extension
  242. *
  243. * @return string|null
  244. */
  245. public function getExtension(){
  246. $deprecated_guesser = "\Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser";
  247. if (class_exists($deprecated_guesser) !== false){
  248. return $deprecated_guesser::getInstance()->guess($this->getMimeType());
  249. }
  250. $guesser = "\Symfony\Component\Mime\MimeTypes";
  251. $extensions = $guesser::getDefault()->getExtensions($this->getMimeType());
  252. return isset($extensions[0]) ? $extensions[0] : null;
  253. }
  254. /**
  255. * Get all attributes
  256. *
  257. * @return array
  258. */
  259. public function getAttributes(){
  260. return $this->attributes;
  261. }
  262. /**
  263. * @return Message
  264. */
  265. public function getMessage(){
  266. return $this->oMessage;
  267. }
  268. /**
  269. * Set the default mask
  270. * @param $mask
  271. *
  272. * @return $this
  273. */
  274. public function setMask($mask){
  275. if(class_exists($mask)){
  276. $this->mask = $mask;
  277. }
  278. return $this;
  279. }
  280. /**
  281. * Get the used default mask
  282. *
  283. * @return string
  284. */
  285. public function getMask(){
  286. return $this->mask;
  287. }
  288. /**
  289. * Get a masked instance by providing a mask name
  290. * @param string|null $mask
  291. *
  292. * @return mixed
  293. * @throws MaskNotFoundException
  294. */
  295. public function mask($mask = null){
  296. $mask = $mask !== null ? $mask : $this->mask;
  297. if(class_exists($mask)){
  298. return new $mask($this);
  299. }
  300. throw new MaskNotFoundException("Unknown mask provided: ".$mask);
  301. }
  302. }