2 // vim: tabstop=2:shiftwidth=2
\r
5 * NP_Moblog ($Revision: 1.137 $)
\r
6 * by hsur ( http://blog.cles.jp/np_cles )
\r
7 * $Id: NP_Moblog.php,v 1.137 2010/06/23 14:20:28 hsur Exp $
\r
9 * Based on NP_HeelloWorld v0.8
\r
10 * http://nakahara21.com/?itemid=133
\r
14 * Copyright (C) 2003 nakahara21 All rights reserved.
\r
15 * Copyright (C) 2004-2010 cles All rights reserved.
\r
17 * This program is free software; you can redistribute it and/or
\r
18 * modify it under the terms of the GNU General Public License
\r
19 * as published by the Free Software Foundation; either version 2
\r
20 * of the License, or (at your option) any later version.
\r
22 * This program is distributed in the hope that it will be useful,
\r
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
25 * GNU General Public License for more details.
\r
27 * You should have received a copy of the GNU General Public License
\r
28 * along with this program; if not, write to the Free Software
\r
29 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
31 * In addition, as a special exception, mamio and cles gives
\r
32 * permission to link the code of this program with those files in the PEAR
\r
33 * library that are licensed under the PHP License (or with modified versions
\r
34 * of those files that use the same license as those files), and distribute
\r
35 * linked combinations including the two. You must obey the GNU General Public
\r
36 * License in all respects for all of the code used other than those files in
\r
37 * the PEAR library that are licensed under the PHP License. If you modify
\r
38 * this file, you may extend this exception to your version of the file,
\r
39 * but you are not obligated to do so. If you do not wish to do so, delete
\r
40 * this exception statement from your version.
\r
43 if (!class_exists('NucleusPlugin')) exit;
\r
45 require_once($DIR_LIBS . 'MEDIA.php');
\r
48 require_once(dirname(__FILE__).'/sharedlibs/sharedlibs.php');
\r
49 require_once('Net/POP3.php');
\r
50 require_once('Mail/mimeDecode.php');
\r
51 require_once('Mail/RFC822.php');
\r
54 $required = '4.3.0';
\r
55 if( ! version_compare(phpversion() , $required , '>=') ){
\r
56 ACTIONLOG :: add(WARNING, 'NP_MoblogはPHP>=4.3.0であることが必要です。');
\r
59 class NP_Moblog extends NucleusPlugin {
\r
62 function getName() {
\r
67 function getAuthor() {
\r
71 // an URL to the plugin website
\r
72 // can also be of the form mailto:foo@bar.com
\r
74 return 'http://blog.cles.jp/np_cles/category/31/subcatid/2';
\r
77 // version of the plugin
\r
78 function getVersion() {
\r
82 function hasAdminArea() {
\r
86 function getEventList() {
\r
87 return array('PrePluginOptionsEdit');
\r
90 function event_PrePluginOptionsEdit(&$data) {
\r
91 switch($data['context']){
\r
94 $m =& MEMBER :: createFromID($data['contextid']);
\r
102 $res = sql_query('SELECT bnumber, bname FROM '.sql_table('blog'));
\r
103 while( $o = mysql_fetch_object($res) ){
\r
104 if( $m->isTeamMember($o->bnumber) ){
\r
105 $blogs[$o->bnumber] = $o->bname;
\r
109 $idandcatTypeInfo = '';
\r
110 foreach($blogs as $blogid => $blogname){
\r
111 $res = sql_query('SELECT catid, cname FROM '.sql_table('category').' WHERE cblog='.$blogid);
\r
112 if( @mysql_num_rows($res) > 0) {
\r
113 while( $o = mysql_fetch_object($res) ){
\r
114 if($idandcatTypeInfo)
\r
115 $idandcatTypeInfo .= '|';
\r
116 $o->cname = strtr($o->cname, $trimChar);
\r
117 $blogname = strtr($blogname, $trimChar);
\r
118 $idandcatTypeInfo .= "{$o->cname} ({$blogname})|{$blogid},{$o->catid}";
\r
122 if( ! $idandcatTypeInfo ){
\r
123 $idandcatTypeInfo = "!!投稿可能なblogがありません!!|0,0";
\r
126 // collection & thumb_col
\r
127 $collections = MEDIA::getCollectionList();
\r
128 $mid = intval($m->getID());
\r
129 $collections[$mid] = 'デフォルト(useridディレクトリ)';
\r
131 $collectionTypeInfo = '';
\r
132 foreach( $collections as $collection => $name ){
\r
133 if($collectionTypeInfo) $collectionTypeInfo .= '|';
\r
134 $name = strtr($name, $trimChar);
\r
135 $collection = strtr($collection, $trimChar);
\r
136 $collectionTypeInfo .= "{$name}|{$collection}";
\r
140 foreach($data['options'] as $oid => $option ){
\r
141 switch($data['options'][$oid]['name']){
\r
143 $data['options'][$oid]['typeinfo'] = $idandcatTypeInfo;
\r
147 $data['options'][$oid]['typeinfo'] = $collectionTypeInfo;
\r
158 function install() {
\r
159 $this->createMemberOption('enable', 'プラグインを有効にするか?', 'yesno', 'no');
\r
161 $this->createMemberOption('host', 'POP3 ホスト名', 'text', 'localhost');
\r
162 $this->createMemberOption('port', 'POP3 ポート', 'text', '110', 'numerical=true');
\r
163 $this->createMemberOption('user', 'POP3 ユーザー名', 'text', '');
\r
164 $this->createMemberOption('pass', 'POP3 パスワード', 'password', '');
\r
165 $this->createMemberOption('useAPOP', 'APOPを使用するか?', 'yesno', 'no');
\r
167 $this->createMemberOption('idandcat', 'Nucleusカテゴリ(Blog)', 'select', '', '');
\r
169 $this->createMemberOption('collection', '画像を保存するディレクトリ', 'select', '', '');
\r
170 $this->createMemberOption('thumb_col', 'サムネイルをを保存するディレクトリ', 'select', '', '');
\r
172 $this->createMemberOption('imgonly', 'イメージ添付メールのみ追加?', 'yesno', 'no');
\r
173 $this->createMemberOption('DefaultPublish', 'デフォルトで公開するか?', 'yesno', 'no');
\r
175 $this->createMemberOption('optionsKeyword', 'オプション記述開始の区切り文字', 'text', '@');
\r
176 $this->createMemberOption('blogKeyword', 'オプションでblogidを指定する場合のキー', 'text', 'b');
\r
177 $this->createMemberOption('categoryKeyword', 'オプションでカテゴリを指定する場合のキー', 'text', 'c');
\r
178 $this->createMemberOption('publishKeyword', 'オプションでストレートにpublish指定する場合のキー', 'text', 's');
\r
180 $this->createMemberOption('moreDelimiter', '追記にする場合の区切り文字(利用しない場合は空欄)', 'text', '');
\r
182 $this->createMemberOption('accept', '投稿許可アドレス(複数の場合改行で区切ってください)', 'textarea', '');
\r
183 $this->createMemberOption('acceptSubjectPrefix','投稿許可SubjectPrefix(制限無しの場合は空欄)','text','');
\r
185 $this->createMemberOption('nosubject', '件名がないときの題名', 'text', '');
\r
186 $this->createMemberOption('no_strip_tags', 'htmlメールの場合に除去しないタグ', 'textarea', '<title><hr><h1><h2><h3><h4><h5><h6><div><p><pre><sup><ul><ol><br><dl><dt><table><caption><tr><li><dd><th><td><a><area><img><form><input><textarea><button><select><option>');
\r
187 $this->createMemberOption('maxbyte', '最大添付量(B)', 'text', '300000', 'numerical=true');
\r
188 $this->createMemberOption('subtype', '対応MIMEタイプ(正規表現)', 'text', 'gif|jpe?g|png|bmp|octet-stream|x-pmd|x-mld|x-mid|x-smd|x-smaf|x-mpeg|pdf');
\r
189 $this->createMemberOption('viri', '保存しないファイル(正規表現)', 'text', '.+\.exe$|.+\.zip$|.+\.pif$|.+\.scr$');
\r
190 $this->createMemberOption('imgExt', '画像ファイルの拡張子(正規表現)', 'text', '.+\.png$|.+\.jpe?g$|.+\.gif$|.+\.bmp$');
\r
192 $this->createMemberOption('thumb_ok', 'サムネイルを使用する?', 'yesno', 'yes');
\r
193 $this->createMemberOption('W', 'サムネイルの大きさ(Width)', 'text', '120', 'numerical=true');
\r
194 $this->createMemberOption('H', 'サムネイルの大きさ(Hight)', 'text', '120', 'numerical=true');
\r
195 $this->createMemberOption('thumb_ext', 'サムネイルを作る対象画像', 'text', '.+\.jpe?g$|.+\.png$');
\r
196 $this->createMemberOption('smallW', 'アイテム内に表示する画像の最大横幅', 'text', '120', 'numerical=true');
\r
198 $this->createMemberOption('textTpl', 'テキストテンプレート', 'textarea', '<%body%>');
\r
199 $this->createMemberOption('withThumbTpl', 'サムネイル付きテンプレート', 'textarea', '<div class="leftbox"><a href="<%mediaUrl%><%imageUrl%>" target="_blank"><%image(<%thumbUrl%>|<%thumbW%>|<%thumbH%>|)%></a></div><%body%>');
\r
200 $this->createMemberOption('withoutThumbTpl', 'サムネイルなしテンプレート', 'textarea', '<div class="leftbox"><%image(<%imageUrl%>|<%sizeW%>|<%sizeH%>|)%></div><%body%>');
\r
201 $this->createMemberOption('reductionTpl', 'サムネイルなしテンプレート(縮小)', 'textarea', '<div class="leftbox"><a href="<%mediaUrl%><%imageUrl%>" target="_blank"><%image(<%imageUrl%>|<%reductionW%>|<%reductionH%>|)%></a></div><%body%>');
\r
202 $this->createMemberOption('dataTpl', 'データファイルテンプレート', 'textarea', '<div class="leftbox"><a href="<%mediaUrl%><%imageUrl%>" target="_blank"><%fileName%></a></div><%body%>');
\r
204 $this->createOption('execMode', '動作モード', 'select', '1', '振分対応モード|0|互換モード|1');
\r
205 $this->createOption('spamCheck', 'SPAMチェックを有効にする', 'yesno', 'no');
\r
207 $this->createOption('interval', 'メール取得の間隔(秒)', 'text', '600', 'numerical=true');
\r
208 $this->createOption('nextUpdate', '次回更新時刻(変更できません)', 'text', '-', 'access=readonly');
\r
209 $this->createOption('lastUpdate', '最終更新時刻(UnixTimeStamp,)', 'text', '0', 'access=hidden');
\r
210 $this->createOption('debug', 'ログを出力を行うか?', 'yesno', 'no');
\r
213 function unInstall() {}
\r
214 function getMinNucleusVersion() { return 320; }
\r
215 function getMinNucleusPatchLevel() { return 0; }
\r
217 // a description to be shown on the installed plugins listing
\r
218 function getDescription() {
\r
219 return '[$Revision: 1.137 $]<br />メールを拾ってアイテムを追加します。<%Moblog%>の記述のあるスキンを適用するページを開くと実行されます。<br />
\r
220 <%Moblog(link)%>と記入することでメールを取得するためのリンクを表示することができます(要ログイン)<br />
\r
221 個人ごとに設定ができるようになりましたので「あなたの設定」か「メンバー管理」から設定を行ってください。';
\r
224 function supportsFeature($what) {
\r
226 case 'SqlTablePrefix' :
\r
234 function _info($msg) {
\r
235 if ($this->getOption('debug') == 'yes') {
\r
236 ACTIONLOG :: add(INFO, 'Moblog: '.$msg);
\r
240 function _warn($msg) {
\r
241 ACTIONLOG :: add(WARNING, 'Moblog: '.$msg);
\r
244 function _getEnableUserId() {
\r
245 $userOptions = $this->getAllMemberOptions('enable');
\r
246 $userIds = Array ();
\r
247 foreach( $userOptions as $userId => $value ){
\r
248 if( $value == 'yes') $userIds[] = $userId;
\r
253 function _initMediaDirByUserId($userId) {
\r
256 $this->_info(__LINE__ . ": ユーザ($userId)の初期設定");
\r
257 $this->memid = $userId;
\r
259 /*-- 受信メールサーバーの設定--*/
\r
260 $this->host = $this->getMemberOption($userId, 'host');
\r
261 $this->port = $this->getMemberOption($userId, 'port');
\r
262 $this->user = $this->getMemberOption($userId, 'user');
\r
263 $this->pass = $this->getMemberOption($userId, 'pass');
\r
265 // メールでアイテムを追加するblogのID
\r
266 $idandcat = $this->getMemberOption($userId, 'idandcat');
\r
267 list($this->blogid, $this->categoryNameOrId) = explode(",", $idandcat);
\r
269 $this->imgonly = ($this->getMemberOption($userId, 'imgonly') == 'yes') ? 1 : 0;
\r
270 $this->DefaultPublish = ($this->getMemberOption($userId, 'DefaultPublish') == 'yes') ? 1 : 0;
\r
272 /*-- メールのタイトルに各種オプションを含める場合の設定--*/
\r
273 $this->optionsKeyword = $this->getMemberOption($userId, 'optionsKeyword');
\r
274 $this->blogKeyword = $this->getMemberOption($userId, 'blogKeyword');
\r
275 $this->categoryKeyword = $this->getMemberOption($userId, 'categoryKeyword');
\r
276 $this->publishKeyword = $this->getMemberOption($userId, 'publishKeyword');
\r
279 $this->accept = explode("\n", $this->getMemberOption($userId, 'accept'));
\r
280 $this->accept = Array_Map("Trim", $this->accept);
\r
281 $this->accept = Array_Map("strtolower", $this->accept);
\r
282 foreach( $this->accept as $mailAddr ){
\r
283 $this->_info(__LINE__ . "許可アドレス user:$userId, $mailAddr");
\r
286 // 投稿許可SubjectPrefix
\r
287 $this->acceptSubjectPrefix = Trim($this->getMemberOption($userId, 'acceptSubjectPrefix'));
\r
290 $this->moreDelimiter = Trim($this->getMemberOption($userId, 'moreDelimiter'));
\r
293 $this->nosubject = $this->getMemberOption($userId, 'nosubject');
\r
294 $this->no_strip_tags = $this->getMemberOption($userId, 'no_strip_tags');
\r
296 // 最大添付量(バイト・1ファイルにつき)※超えるものは保存しない
\r
297 $this->maxbyte = $this->getMemberOption($userId, 'maxbyte');
\r
298 $this->subtype = $this->getMemberOption($userId, 'subtype');
\r
299 $this->viri = $this->getMemberOption($userId, 'viri');
\r
300 $this->imgExt = $this->getMemberOption($userId, 'imgExt');
\r
303 $this->thumb_ok = ($this->getMemberOption($userId, 'thumb_ok') == 'yes') ? 1 : 0;
\r
304 $this->W = $this->getMemberOption($userId, 'W');
\r
305 $this->H = $this->getMemberOption($userId, 'H');
\r
306 $this->thumb_ext = $this->getMemberOption($userId, 'thumb_ext');
\r
307 $this->smallW = $this->getMemberOption($userId, 'smallW');
\r
310 $collections = MEDIA::getCollectionList();
\r
311 $collection = $this->getMemberOption($userId, 'collection');
\r
312 if( $collection && isset($collections[$collection]) ){
\r
313 $this->collection = $collection;
\r
315 $this->_info(__LINE__ . ": 画像保存ディレクトリが正しくありません。デフォルトを使用します");
\r
316 $this->collection = $this->memid;
\r
319 $this->tmpdir = $DIR_MEDIA.$this->collection.'/';
\r
320 $this->_info(__LINE__ . ": 画像保存ディレクトリ: $this->tmpdir");
\r
322 if (!@is_dir($this->tmpdir)) {
\r
323 $this->_warn(__LINE__ . ": {$DIR_MEDIA}.{$this->collection} ディレクトリが存在しないので、ディレクトリを作成します。");
\r
324 $oldumask = umask(0000);
\r
325 if (!@mkdir($this->tmpdir, 0777))
\r
326 return $this->_warn(__LINE__ . ": 設定エラー: {$DIR_MEDIA}.{$this->collection} ディレクトリの作成に失敗しました。パーミッションを確認してください。");
\r
330 if (!is_writable($this->tmpdir)) {
\r
331 $this->_warn(__LINE__ . ": 設定エラー: {$DIR_MEDIA}.{$this->collection} ディレクトリが存在しないか、書き込み可能になっていません");
\r
335 $thumb_collection = $this->getMemberOption($userId, 'thumb_col');
\r
336 if( $collection && isset($collections[$thumb_collection]) ){
\r
337 $this->thumb_collection = $thumb_collection;
\r
339 $this->_info(__LINE__ . ": サムネイル画像保存ディレクトリが正しくありません。デフォルトを使用します");
\r
340 $this->thumb_collection = $this->memid;
\r
343 $this->thumb_dir = $DIR_MEDIA.$this->thumb_collection.'/';
\r
344 $this->_info(__LINE__ . ": サムネイル画像保存ディレクトリ: $this->thumb_dir");
\r
346 if (!@is_dir($this->thumb_dir)) {
\r
347 $this->_warn(__LINE__ . ": {$DIR_MEDIA}.{$this->thumb_dir} ディレクトリが存在しないので、ディレクトリを作成します。");
\r
348 $oldumask = umask(0000);
\r
349 if (!@mkdir($this->thumb_dir, 0777))
\r
350 return $this->_warn(__LINE__ . ": 設定エラー: {$DIR_MEDIA}.{$this->thumb_dir} ディレクトリの作成に失敗しました。パーミッションを確認してください。");
\r
354 if (!is_writable($this->thumb_dir)) {
\r
355 $this->_warn(__LINE__ . ": 設定エラー: {$DIR_MEDIA}.{$this->thumb_dir} ディレクトリが存在しないか、書き込み可能になっていません");
\r
359 function _convert($str, $input_encoding = false) {
\r
360 if( ! $input_encoding ){
\r
361 $input_encoding = "ISO-2022-JP,ASCII,JIS,UTF-8,EUC-JP,SJIS,ISO-2022-JP";
\r
362 $encoding = mb_detect_encoding($str, $input_encoding);
\r
364 $input_encoding = "ISO-2022-JP";
\r
366 return mb_convert_encoding($str, _CHARSET, $input_encoding);
\r
369 function _addr_search($str) {
\r
370 if( PEAR::isError($addresses = Mail_RFC822::parseAddressList($str)) ){
\r
373 $addr = array_shift($addresses);
\r
375 return $addr->mailbox . "@" .$addr->host;
\r
379 function _thumb_create($src, $W, $H, $thumb_dir = "./") {
\r
381 $size = GetImageSize($src);
\r
382 switch ($size[2]) {
\r
387 $im_in = @ImageCreateFromJPEG($src);
\r
390 $im_in = @ImageCreateFromPNG($src);
\r
394 $this->_warn(__LINE__ . ": GDをサポートしていないか、ソースが見つかりません<br>phpinfo()でGDオプションを確認してください");
\r
398 if ($size[0] > $W || $size[1] > $H) {
\r
399 $key_w = $W / $size[0];
\r
400 $key_h = $H / $size[1];
\r
401 ($key_w < $key_h) ? $keys = $key_w : $keys = $key_h;
\r
402 $out_w = $size[0] * $keys;
\r
403 $out_h = $size[1] * $keys;
\r
408 // 出力画像(サムネイル)のイメージを作成し、元画像をコピーします。(GD2.0用)
\r
409 $im_out = ImageCreateTrueColor($out_w, $out_h);
\r
410 $resize = ImageCopyResampled($im_out, $im_in, 0, 0, 0, 0, $out_w, $out_h, $size[0], $size[1]);
\r
412 // サムネイル画像をブラウザに出力、保存
\r
413 $filename = substr($src, strrpos($src, "/") + 1);
\r
414 ImageJPEG($im_out, $thumb_dir.$this->_getThumbFileName($filename)); //jpgサムネイル作成
\r
416 ImageDestroy($im_in);
\r
417 ImageDestroy($im_out);
\r
419 $this->_info(__LINE__ . ": サムネイルを作成しました" . $thumb_dir.$this->_getThumbFileName($filename));
\r
423 function _getThumbFileName($filename){
\r
424 $filename = substr($filename, 0, strrpos($filename, "."));
\r
425 return $filename."-small.jpg";
\r
428 function _getExecuteLink() {
\r
430 return $CONF['ActionURL'].'?action=plugin&name=Moblog&type=execute';
\r
433 function _checkLastupdate() {
\r
435 $lastUpdate = $this->getOption('lastUpdate');
\r
436 $interval = $this->getOption('interval');
\r
438 if ($lastUpdate + $interval < $now) {
\r
439 $this->setOption('lastUpdate', $now);
\r
440 $this->setOption('nextUpdate', date("Y-m-d H:i:s", $lastUpdate + $interval));
\r
441 $this->_info(__LINE__ . ": 更新します。");
\r
444 $this->_info(__LINE__ . ": 更新しません。次回更新は".date("Y-m-d H:i:s", $lastUpdate + $interval)."以降です。");
\r
448 function doSkinVar($skinType, $type = "") {
\r
453 if ( $this->_checkLastupdate() )
\r
458 if ( $member->isLoggedIn() )
\r
459 echo '<a href="'.$this->_getExecuteLink().'">Add Item by Mail</a>';
\r
462 } //end of function doSkinVar($skinType)
\r
464 function doAction($type) {
\r
470 if (!$member->isLoggedIn())
\r
471 return "ログインが必要です";
\r
473 header('Location: ' . serverVar('HTTP_REFERER'));
\r
477 return 'アクションが定義されていません: '.$type;
\r
481 function execute() {
\r
482 $this->execMode = intval($this->getOption('execMode'));
\r
483 if( $this->execMode == 0 ){
\r
485 $this->_info(__LINE__ . ": 振分対応モードで動作します。");
\r
486 } elseif ( $this->execMode == 1 ) {
\r
488 $this->_info(__LINE__ . ": 互換モードで動作します");
\r
491 $enabledUserIds = $this->_getEnableUserId();
\r
492 foreach ($enabledUserIds as $userId) {
\r
493 $this->_info(__LINE__ . ": ユーザ($userId)のメールを取得開始します");
\r
494 $this->_initMediaDirByUserId($userId);
\r
497 $pop3 =& new Net_POP3();
\r
498 $pop3->_timeout = 10;
\r
500 if( ! $pop3->connect($this->host, $this->port) ){
\r
501 $this->_warn(__LINE__ . ": POPサーバーに接続できません");
\r
506 $authMethod = $this->getMemberOption($this->memid, 'useAPOP') == 'yes' ? 'APOP' : 'USER';
\r
507 $this->_info(__LINE__ . ": $authMethod で認証を行います");
\r
508 if(PEAR::isError($ret =& $pop3->login($this->user , $this->pass , $authMethod)) ){
\r
509 $this->_warn(__LINE__ . ": 認証に失敗しました:" . $ret->getMessage() );
\r
510 $pop3->disconnect();
\r
515 $num = $pop3->numMsg();
\r
516 $this->_info(__LINE__ . ": $num 件のメールがあります");
\r
518 $pop3->disconnect();
\r
523 for ($i = 1; $i <= $num; $i ++) {
\r
524 if(! $msg =& $pop3->getMsg($i) ){
\r
525 $this->_warn(__LINE__ . ": メールの取得に失敗しました。");
\r
528 $result = $this->addItemByMail($userId, $msg);
\r
530 $this->_info(__LINE__ . ": メッセージを削除します");
\r
531 $pop3->deleteMsg($i);
\r
535 $pop3->disconnect();
\r
536 $this->_info(__LINE__ . ": ユーザ($userId)のメールを取得終了しました");
\r
540 function addItemByMail($userId, $msg) {
\r
542 $params['include_bodies'] = TRUE;
\r
543 $params['decode_bodies'] = TRUE;
\r
544 $params['decode_headers'] = TRUE;
\r
545 $params['input'] = $msg;
\r
546 if(PEAR::isError( $decodedMsg = Mail_mimeDecode::decode($params)) ){
\r
547 $this->_warn(__LINE__ . ": メールデコードに失敗しました:" . $decodedMsg->getMessage() );
\r
552 if ( $decodedMsg->headers['from'] ) {
\r
553 $from = $this->_addr_search($decodedMsg->headers['from']);
\r
555 if ( (! $from ) && $decodedMsg->headers['reply-to'] ) {
\r
556 $from = $this->_addr_search($decodedMsg->headers['reply-to']);
\r
558 if ( (! $from ) && $decodedMsg->headers['return-path'] ) {
\r
559 $from = $this->_addr_search($decodedMsg->headers['return-path']);
\r
562 $this->_warn(__LINE__ . ": メールに送信者アドレスが見つかりません");
\r
565 $this->_info(__LINE__ . ": From($from)");
\r
568 $from = strtolower(Trim($from));
\r
569 if ( in_array($from, $this->accept) ) {
\r
570 $this->_info(__LINE__ . ": 投稿許可アドレスに含まれているので受付($from)");
\r
571 } elseif( in_array( "*", $this->accept) ){
\r
572 $this->_info(__LINE__ . ": 投稿許可アドレスにワイルドカードが含まれているので受付($from)");
\r
574 if( $this->execMode == 0 ){
\r
575 $this->_info(__LINE__ . ": 投稿許可アドレスに含まれていないので拒否($from)。振り分け対応モードなので他のアカウントで取得が行われる場合があります。");
\r
577 $this->_warn(__LINE__ . ": 投稿許可アドレスに含まれていないので拒否($from)");
\r
581 return $this->execMode;
\r
585 $blog =& new BLOG($this->blogid);
\r
587 $timestamp = strtotime( trim($decodedMsg->headers['date']) );
\r
588 if ($timestamp == -1){
\r
589 $this->_info(__LINE__ . ": Dateヘッダからのtimestamp取得に失敗しました。");
\r
592 $timestamp = $blog->getCorrectTime($timestamp);
\r
595 $subject = $this->_convert($decodedMsg->headers['subject']);
\r
597 // Subject: prefixチェック
\r
598 if ( $this->acceptSubjectPrefix ){
\r
599 $this->_info(__LINE__ . ": 投稿許可SubjectPrefixがあります(prefix: $this->acceptSubjectPrefix)");
\r
600 $pos = mb_strpos($subject, $this->acceptSubjectPrefix);
\r
603 $subject = mb_substr($subject, mb_strlen($this->acceptSubjectPrefix) );
\r
604 $this->_info(__LINE__ . ": 投稿許可SubjectPrefixをみつけました(prefix削除後subject: $subject)");
\r
606 $this->_warn(__LINE__ . ": 投稿許可SubjectPrefixがないので拒否します($subject)");
\r
611 // subject: オプション分割
\r
612 if (preg_match('/'.$this->optionsKeyword.'/i', $subject)) {
\r
613 list ($subject, $option) = spliti($this->optionsKeyword, $subject, 2);
\r
615 $this->_info(__LINE__ . ": Subject($subject), Option($option)");
\r
617 $option = '&'.$option;
\r
618 if (preg_match('/&' . $this->blogKeyword . '=([^&=]+)/i', $option, $word)) {
\r
619 $this->blogid = $word[1];
\r
620 $this->_info(__LINE__ . ': blogidを' . $this->blogid . 'で上書きします');
\r
622 if (preg_match('/&' . $this->categoryKeyword . '=([^&=]+)/i', $option, $word)) {
\r
623 $this->categoryNameOrId = $word[1];
\r
624 $this->_info(__LINE__ . ': Categoryを' . $this->categoryNameOrId . 'で上書きします');
\r
626 if (preg_match('/&' . $this->publishKeyword . '=([^&=]+)/i', $option, $word)) {
\r
627 $this->DefaultPublish = $word[1];
\r
628 $this->_info(__LINE__ . ($this->DefaultPublish ? ': 投稿を公開に上書きします' : ': 投稿を下書きに上書きします'));
\r
633 if( ! $subject = trim(htmlspecialchars($subject, ENT_QUOTES)) ){
\r
634 $subject = $this->nosubject;
\r
639 if( strtolower($decodedMsg->ctype_primary) == "text" ){
\r
640 $this->_info(__LINE__ . ": single partメッセージです");
\r
641 $text = $this->_textPart($decodedMsg);
\r
642 } elseif ( strtolower($decodedMsg->ctype_primary) == "multipart" ){
\r
643 $this->_info(__LINE__ . ": multipart partメッセージです");
\r
645 $fileNames = Array();
\r
646 $this->_decodeMultiPart($decodedMsg->parts, $texts, $fileNames);
\r
648 $text = $texts['plain'];
\r
649 if( $texts['html'] ) $text = $texts['html'];
\r
652 if ($this->imgonly && (! $fileNames) ) {
\r
653 $this->_info(__LINE__ . ": 添付ファイルがないので書き込みません");
\r
657 if( $this->_isSpam($text) ){
\r
658 $this->_warn(__LINE__ . ": SPAMのため追加しません");
\r
664 if ( ! $fileNames ) {
\r
665 // 添付ファイルがない場合のbody
\r
670 $body .= TEMPLATE :: fill($this->getMemberOption($this->memid, 'textTpl'), $vars);
\r
672 // 添付ファイルがある場合のbody
\r
673 $lastFile = array_pop($fileNames);
\r
675 foreach( $fileNames as $filename ){
\r
676 $body .= $this->_imageHtml($filename);
\r
679 $body .= $this->_imageHtml($lastFile, $text);
\r
683 $this->_info(__LINE__ . ": アイテム追加します");
\r
685 // bodyをbodyとmoreに分割
\r
687 if( $this->moreDelimiter )
\r
688 list($body, $more) = spliti($this->moreDelimiter, $body, 2);
\r
690 $body = trim($body);
\r
691 $more = trim($more);
\r
693 $this->_addDatedItem($this->blogid, $subject, $body, $more, 0, $timestamp, 0, $this->categoryNameOrId);
\r
697 function _decodeMultiPart($parts, &$texts, &$fileNames){
\r
698 foreach($parts as $part){
\r switch ( strtolower( $part->ctype_primary )){
\r
701 $this->_decodeMultiPart($part->parts, $texts, $fileNames);
\r
705 $this->_info(__LINE__ . ": text part をみつけました[{$part->ctype_primary}/{$part->ctype_secondary}]");
\r
706 $texts[$part->ctype_secondary] = $this->_textPart($part);
\r
711 $this->_info(__LINE__ . ": image/data part をみつけました[{$part->ctype_primary}/{$part->ctype_secondary}]");
\r
712 if( $fileName = $this->_imagePart($part) )
\r
713 $fileNames[] = $fileName;
\r
719 function _textPart(&$part){
\r
721 if( $part->ctype_parameters )
\r
722 $encoding = $this->ctype_parameters['charset'];
\r
724 $text = $this->_convert($part->body, $encoding);
\r
725 $text = strip_tags($text, $this->no_strip_tags);
\r
727 $blog =& new BLOG($this->blogid);
\r
728 //blog設定で改行を<br />に置換onの場合
\r
729 if ($blog->getSetting('bconvertbreaks')) {
\r
730 if ( strtolower($part->ctype_secondary) == 'html' ) {
\r
731 //改行文字を削除、<br>タグを\nへ
\r
732 $text = str_replace("\r\n", "\r", $text);
\r
733 $text = str_replace("\r", "\n", $text);
\r
734 $text = str_replace("\n", "", $text);
\r
735 $text = str_replace("<br>", "\n", $text);
\r
741 function _imagePart(&$part){
\r
742 if( !$this->prefixDate ){
\r
743 $this->prefixDate = date('YmdHis');
\r
744 $this->fileCount = 0;
\r
746 $this->fileCount += 1;
\r
748 $this->filePrefix = $this->prefixDate . sprintf('%02d', $this->fileCount);
\r
751 if( $part->d_parameters ){
\r
752 $filename = $part->d_parameters['filename'];
\r
753 } elseif( $part->ctype_parameters ){
\r
754 $filename = $part->ctype_parameters['name'];
\r
756 $filename = $part->ctype_secondary;
\r
759 $filename = $this->_convert($filename);
\r
760 $filename = $this->filePrefix . "-" . $filename;
\r
761 $this->_info(__LINE__ . ": FileName($filename)");
\r
764 $size = strlen($part->body);
\r
765 if( preg_match("/".$this->subtype."/i", trim($part->ctype_secondary) )){
\r
767 if ($size < $this->maxbyte && !preg_match("/".$this->viri.'/i', $filename)) {
\r
769 $fp = fopen($this->tmpdir.$filename, "w");
\r
770 fputs($fp, $part->body);
\r
773 $size = @getimagesize($this->tmpdir.$filename);
\r
775 if ($this->thumb_ok && function_exists('ImageCreate')) {
\r
777 if ( preg_match("/$this->thumb_ext/i", $filename) ) {
\r
778 if ($size[0] > $this->W || $size[1] > $this->H) {
\r
779 $this->_thumb_create($this->tmpdir.$filename, $this->W, $this->H, $this->thumb_dir);
\r
785 $this->_warn(__LINE__ . ": 添付ファイルを無視します。(サイズ超過: $size B or 保存しないファイルに該当しています) [$part->ctype_primary/$part->ctype_secondary]");
\r
788 $this->_warn(__LINE__ . ": 添付ファイルを無視します。(subtypeチェック: $part->ctype_secondary が対応MIMEタイプに入っていますか?) [$part->ctype_primary/$part->ctype_secondary]");
\r
792 function _imageHtml($filename, $body = ""){
\r
795 $size = @getimagesize($this->tmpdir.$filename);
\r
796 $thumb_size = @getimagesize($this->thumb_dir.$this->_getThumbFileName($filename));
\r
797 $smallH = round($this->smallW / $size[0] * $size[1], 0);
\r
800 'thumbW' => $thumb_size[0],
\r
801 'thumbH' => $thumb_size[1],
\r
802 'reductionW' => $this->smallW,
\r
803 'reductionH' => $smallH,
\r
804 'sizeW' => $size[0],
\r
805 'sizeH' => $size[1],
\r
807 'thumbUrl' => $this->thumb_collection.'/' . urlencode($this->_getThumbFileName($filename)),
\r
808 'imageUrl' => $this->collection.'/' . urlencode($filename),
\r
809 'mediaUrl' => $CONF['MediaURL'],
\r
810 'fileName' => $filename
\r
814 if( ! preg_match("/$this->imgExt/i", $filename) ){
\r
815 $this->_info(__LINE__ . ": 画像ファイルに該当しないので、データファイルテンプレートを使用します");
\r
816 return TEMPLATE :: fill($this->getMemberOption($this->memid, 'dataTpl'), $vars);
\r
819 if ( $thumb_size[0] ) { //サムネイルがある場合のソース
\r
820 $this->_info(__LINE__ . ": サムネイルがあります");
\r
821 return TEMPLATE :: fill($this->getMemberOption($this->memid, 'withThumbTpl'), $vars);
\r
822 } else { //サムネイルがない場合のソース
\r
823 if ($size[0] > $this->smallW) { //縮小表示
\r
824 $this->_info(__LINE__ . ": サムネイルがありません、縮小表示します");
\r
825 return TEMPLATE :: fill($this->getMemberOption($this->memid, 'reductionTpl'), $vars);
\r
827 $this->_info(__LINE__ . ": サムネイルがありません");
\r
828 return TEMPLATE :: fill($this->getMemberOption($this->memid, 'withoutThumbTpl'), $vars);
\r
833 function _addDatedItem($blogid, $title, $body, $more, $closed, $timestamp, $future, $catNameOrId = "") {
\r
834 // 1. ログイン======================
\r
835 $mem = MEMBER :: createFromID($this->memid);
\r
837 // 2. ブログ追加できるかチェック======================
\r
838 if (!BLOG :: existsID($this->blogid)) {
\r
839 $this->_info(__LINE__ . ": 存在しないblogです");
\r
842 $this->_info(__LINE__ . ": blogidはOK!");
\r
844 if (!$mem->isTeamMember($blogid)) {
\r
845 $this->_warn(__LINE__ . ": メンバーではありません");
\r
848 $this->_info(__LINE__ . ": メンバーチェックもok!");
\r
850 if (!trim($body)) {
\r
851 $this->_warn(__LINE__ . ": 空のアイテムは追加できません");
\r
854 $this->_info(__LINE__ . ": アイテムは空じゃないです");
\r
857 $blog =& new BLOG($this->blogid);
\r
858 if( $blog->isValidCategory($catNameOrId) ){
\r
859 // カテゴリIDとして有効なときはそのまま使う
\r
860 $catid = $catNameOrId;
\r
862 // カテゴリID ゲット (誤ったカテゴリID使用時はデフォを使用)
\r
863 $catid = $blog->getCategoryIdFromName($catNameOrId);
\r
866 $this->_info(__LINE__ . ": 追加するcatid: ".$catid);
\r
867 if ($this->DefaultPublish) {
\r
870 $draft = 1; //ドラフト追加
\r
871 $this->_info(__LINE__ . ": ドラフトで追加します");
\r
874 $closed = 0; //コメントを許可
\r
875 $this->_info(__LINE__ . ": \$catid:".$catid.", \$draft:".$draft.", \$closed:".$closed);
\r
878 $itemid = $blog->additem($catid, $title, $body, $more, $blogid, $mem->getID(), $timestamp, $closed, $draft);
\r
880 $this->_info(__LINE__ . ": itemid: $itemid");
\r
884 function _isSpam($str){
\r
886 if( $this->getOption('spamCheck') == 'yes' ){
\r
887 $spamcheck = array (
\r
888 'type' => 'Moblog',
\r
893 $manager->notify('SpamCheck', array ('spamcheck' => & $spamcheck));
\r
894 if (isset($spamcheck['result']) && $spamcheck['result'] == true)
\r