カテゴリー : programming

メール投稿した画像をサーバに保存する方法

※この記事は,ウェブアプリ(プログラミング)に関するページです

興味のある方のみ御覧ください。

iPhone(iPod touch)のSafariでは

アップロードフォームが無効化されています。

iphoneから,自分のレンタルサーバの,指定するディレクトリへ

ファイル名を指定してアップロードすることは困難です。

(800円出すならば,FTP On The Goで片付ける手もあります)

また,メールし放題のプランに入っている不肖の身として

携帯からのアップロードは,写メですれば無料ということもあり

メールから自レンタルサーバに画像をアップロードする

PHPスクリプトを書くことにしました。

動作確認はXREAサーバ(PHP 5.25,Apache 1.3.37)で

セーフモードでの実行で確認しています。

必要要件は,PEARのNet_POP3Mail_MimeDecodeがインストールされていること。

PHP4.3以上ぐらいであれば動作すると思うのですが

確認環境がないこともあり,保証はしません。

スクリプトのダウンロードはここから

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?php
//データの保存ディレクトリ(最後に必ず「/」を入れる)
//あと適切なパーミションを与えておく。
$dir='/***/public_html/pictures/';

//gmailのアカウント情報
$gmail_name='あなたのアカウント名@gmail.com';
$gmail_pwd='gmailのパスワード';
 
//     ↑設定ここまで↑

//PEARの読み込み
require_once 'Net/POP3.php';
require_once 'Mail/mimeDecode.php';

$pop3=&new Net_POP3();
//gmailに接続
if($pop3->connect('ssl://pop.gmail.com',995)){
  //gmailへのログイン処理
  if($pop3->login($gmail_name,$gmail_pwd)){
    //未読メールリストの取得
    $list=$pop3->getListing();
   
    //未読メールを一件ずつ処理
    for($i=0;$i<count($list);$i++){
      //メールデータを取得
      $msg=$pop3->getMsg($list[$i]['msg_id']);
     
      //MAIL_mimeDecodeの初期化
      $decoder=new Mail_mimeDecode($msg);
     
      //パラメータの設定
      $structure=$decoder->decode(
        array(
        'include_bodies'=>true,
        'decode_bodies'=>true,
        'decode_headers'=>true
        )
      );
     
      if(file_exists($dir.$filename)){
        //die('重複ファイルがあるので処理を終了します。');
      }
      //マルチパートを1パートずつ処理
      foreach($structure->parts as $parts){
        switch(strtolower($parts->ctype_secondary)){
          //保存除外項目
          //(jpegを保存したくなければcase 'jpeg':を追加)
          case 'plain':
          case 'html':
          break;
          //それ以外は保存
          default:
          /*今回は件名にファイル名を指定している設定
          処理を簡潔にするために半角英数記号のみ使うことを想定*/

         
          //件名を取得
          $filename=$structure->headers['subject'];
         
          //保存処理
          $fp=fopen($dir.$filename,'w+');
          fputs($fp,$parts->body);
          fclose($fp);
         
          //1メールにつき1ファイル添付の設計なので
          //このメールの処理は終了(foreachレベルまでbreak)
          break(2);
        }
      }
     
      if(file_exists($dir.$filename)){//ファイルが保存できている
        //メールをサーバから削除
        $pop3->deleteMsg($list[$i]['msg_id']);
        //メッセージの表示
        echo $filename.'の保存に成功しました';
      }else{//ファイルが保存できていない場合
        //メッセージの表示
        echo $filename.'の保存に失敗しました';
      }
    }
  }else{
    echo 'gmailへのログインに失敗しました。';
  }
}else{
  echo 'gmailへの接続に失敗しました';
}
?>

設定する項目は,4行目の保存ディレクトリと,

7,8行目のgmailアカウント情報です。

処理を煩雑にさせないためにも,

専用のgmailアカウントを用意するのが良いと思います。

あとPOP3アクセスを有効にするのをお忘れないように。

このgmailアカウントに

ファイルを1つのみ添付し,件名にファイル名を指定

することで,ファイルをアップロードするような仕様としています。

件名に「test.jpg」と指定して添付送信すれば

test.jpgがサーバに保存されます。

42行目のコメントアウトを外してもらえれば,重複するファイルがあった場合

保存しなくなります。

察しの良い方は気づかれたかも知れませんが,

4行目の$dirをpublic_htmlレベルまでにしておいて,

件名で「pictures2/test.jpg」とすれば

異なるディレクトリへのアップも可能です。

1メール複数ファイルの添付や,元ファイル名を使っての保存は

スクリプトが煩雑になるため,今回は採用しませんでした。

これをcronで定期実行すれば,メールで画像アップロードできますし

cronが使えない環境であれば,画像をアップしたあと,

Safariなり携帯なりで,ページにアクセスしてPHPを実行すれば良いことです。

投稿者を限定したい場合は,PHPのスクリプトに組み込むよりも

gmailのフィルター機能で投稿元アドレスを限定すれば良いと思います。

携帯のメールで,擬似的に差出人を任意アドレスに設定し,送信する

携帯メールの最大の欠点として,

差出人(送信元)アドレスを自由に設定できない

という欠点がある。

アプリやWebメールを使う手もあるが,

パケット代・手間を考えると気が進まない。

やはり手間を考えると,標準の携帯メーラーから

送信元アドレスを自由に設定して送れないものか。

メール使いホーダイに入っていれば,定額で実現できるし。

 

色々考えた末

GmailとPHPとcronを使えば,実現できるのでは?

ということで,PEAR::Mail, PEAR::Net_POP3を使いやってみた。

結果は,可能だし,実用的。

欠点は,予め送信したいアドレスにid numberを割り振り,

配列やDBに登録しておく必要があること。

(未登録のアドレスには送信できない)

アルゴリズムは次の通り。

1. 携帯から「To: xxx+###@gmail.com」へ送信する。

「xxx+###@gmail.com」というアドレスに送信しても,

“+”以降はGmailでは無視され「xxx@gmail.com」に届く。

例として,xxx+000@gmail.comに送ったと仮定する。

2. Gmail「xxx@gmail.com」にメールが届く
3.PHPでメールを転送する

GmailからPOP3でメールを取得しSMTPで送信(転送)

SMTPで送信する際,ヘッダーを設定するのだが

Return-PathとFromに任意のアドレスを設定できる。

「xxx+000@gmail.com」の000をidとして

予め対応するアドレスを配列なりDBに登録しておくことで

(例: 000->xxx@yyy.com)

###の部分を変えれば,任意の相手に送信することができる。要するに

xxx+000@gmail.com: xxx@yyy.comへ転送

xxx+001@gmail.com: aaa@bbb.comへ転送

xxx+002@gmail.com: ccc@ddd.comへ転送

xxx+000.001@gmail.com: xxx@yyy.com, aaa@bbb.comへ転送(複数)

このPHPをcronで定期実行することで,

定期的にGmailをチェック,転送させる。

 

gmailで送受信するためのクラス(gmail)を作成し

それを用いて送受信するようにした。

例)メールの送信
 
<?phprequire_once 'gmail.php';$gm=new gmail();$gm->set_account_info('xxx@gmail.com','password');

$header=array('From'=>'aaa@bbb.com','To'=>'yyy@gmail.com','Subject'=>'Test');$body='メール本文';

$gm->send(array('to'=>'yyy@gmail.com','header'=>$header,'body'=>$body));?>
 

cron.sh

#!/bin/sh<br />#PHP<br />/usr/local/bin/php /***/***/main.php<br />exit

main.php

<br />&lt;?php<br />require 'gmail.php';<br />$gm=new gmail();<br />$gm-&gt;set_account_info(<br /> 'xxx@gmail.com','password'<br />);<br />$p=0;<br />while(TRUE):<br />   $msg=$gm-&gt;getMessage($p);<br />  if($msg===FALSE){break;}<br />  $arry=explode('+',$msg['header']['To']);<br />  $arry=explode('@',$arry[1]);<br />  $arry=explode('.',$arry[0]);<br />  $tol=array();<br /> foreach($arry as $eac):<br />       $tol[]=$ir-&gt;get_addr_by_sn($eac);<br />  endforeach;<br />   $header=array(<br />        'To'=&gt;implode(', ',$tol),<br />      'From'=&gt;'
xxx@yyy.com
',//差出人を設定<br />        'Subject'=&gt;$msg['header']['Subject'],<br />      'Return-Path'=&gt;'xxx@yyy.com',//差出人を設定<br />      'MIME-Version'=&gt;$msg['header']['MIME-Version'],<br />        'Content-Type'=&gt;$msg['header']['Content-Type'],<br />        'Content-Transfer-Encoding'=&gt;$msg['header']['Content-Transfer-Encoding'],<br />      'Date'=&gt;$msg['header']['Date'],//携帯からの送信日時と同じにする場合設定<br />     'X-Priority'=&gt;3<br />    );<br />    if(count($tol)&gt;0):<br /> $gm-&gt;send(array(<br />       'to'=&gt;$tol,<br />        'header'=&gt;$header,<br />     'body'=&gt;$msg['body'],<br />      'body_encode'=&gt;FALSE<br />   ));<br />   endif;<br />    $p++;<br /> if($p&gt;3){break;}//1回に処理するのは3通までに設定<br />endwhile;<br />?&gt;

gmail.php

&lt;?php<br />require_once 'Mail.php';<br />require_once 'Mail/mime.php';<br />require_once 'Net/POP3.php';<br />mb_language('ja');<br />mb_internal_encoding('iso-2022-jp');<br />class gmail{<br />   function __construct(){<br />       $this-&gt;par=array(<br />      'pop3'=&gt;array(<br />         'host'=&gt;'ssl://pop.gmail.com',<br />         'port'=&gt;'995',<br />     ),'smtp'=&gt;array(<br />           'host'=&gt;'smtp.gmail.com',<br />          'port'=&gt;587,<br />           'auth'=&gt;true,<br />          'debug'=&gt;true<br />      ));<br />   }<br /><br />   function set_account_info($usr,$pwd,$smtpusr='',$smtppwd=''){<br />     $this-&gt;par['username']=$usr;<br />       $this-&gt;par['password']=$pwd;<br />       if($smtpusr==''){$smtpusr=$usr;}<br />      if($smtppwd==''){$smtppwd=$pwd;}<br />      $this-&gt;par['smtp']['username']=$smtpusr;<br />       $this-&gt;par['smtp']['password']=$smtppwd;<br />   }<br /><br />   function send($arg){<br />      if($arg['body_encode']!==FALSE):<br />      $arg['body']=mb_convert_encoding($arg['body'],'ISO-2022-JP','auto');<br />      endif;<br />        $mo=Mail::factory('smtp',$this-&gt;par['smtp']);<br />      $ret=$mo-&gt;send($arg['to'],$arg['header'],$arg['body']);<br />        if(PEAR::isError($ret)):<br />          die('Error: '.$ret-&gt;getMessage());<br />     endif;<br />    }<br /><br />   function getMessage($pointer,$del=TRUE){<br />      if(!$this-&gt;connect_pop3()){die('connect error');}<br />      $res=array();<br />     $list=$this-&gt;pop3-&gt;getListing();<br />        if(count($list)&lt;$pointer+1):<br />           return FALSE;<br />     else:<br />         $res['header']=$this-&gt;pop3-&gt;getParsedHeaders($list[$pointer]['msg_id']);<br />            $res['body']=$this-&gt;pop3-&gt;getBody($list[$pointer]['msg_id']);<br />           if($del){$this-&gt;pop3-&gt;deleteMsg($list[$pointer]['msg_id']);}<br />            return $res;<br />      endif;<br />    }<br /><br />   function connect_pop3(){<br />      if(is_null($this-&gt;pop3)):<br />          $this-&gt;pop3=&amp;new Net_POP3();<br />           if($this-&gt;pop3-&gt;connect($this-&gt;par['pop3']['host'],$this-&gt;par['pop3']['port'])):<br />              if($this-&gt;pop3-&gt;login($this-&gt;par['username'],$this-&gt;par['password'])):<br />                else:<br />                 return FALSE;<br />             endif;<br />            else:<br />             return FALSE;<br />         endif;<br />        endif;<br />        return TRUE;<br />  }<br /> function __destruct(){<br />        if(!is_null($this-&gt;pop3)):<br />         $this-&gt;pop3-&gt;disconnect();<br />      endif;<br />    }<br />}<br />?&gt;