[PHP]ユーザー定義関数の出力結果を任意の変数に格納する

通常ユーザー定義関数の出力結果は return で戻り値(返り値)として返すのが一般的ですが、
preg_match() の $match のように結果を指定された変数に保存したい場合や、 エラー発生時に任意の変数にエラーコードを格納したい場合などがあると思います。
そういった場合は引数に & を付けて参照渡しにします。(参照渡しについて

下の例では2つの数値を足した結果を任意の変数に格納しています。

<?php
sample(3, 4, $result);
echo $result;

function sample($a, $b, &$x){
	$x = $a + $b;
}

【出力結果】

7

変数 $x を参照渡しにすることで、$x に与えられた変更が $result に影響するようにしています。

次の例では関数 sample() に渡された文字列が「ok」でない場合エラーコード(例では「Error 123」)を 変数 $code に格納します。

<?php
$value = 'test';

$result = sample($value, $code);
var_dump($result);
echo $code;

function sample($value, &$error=null){
	if($value == 'ok'){
		return true;
	} else {
		$error = "Error 123";
		return false;
	}
}

【出力結果】

boolean false
Error 123

エラーコードをどの変数に格納するかは関数 sample() の第 2 引数 $error に & をつけて指定しています。
引数 $error には初期値を設定してあるのでエラーコードを受け取る必要がない場合は引数を省略できます。
例では格納先に変数 $code を指定していますが、「$err」を指定すれば「$err」に格納されます。

[PHP]ソケット接続(fsockopen)でメール受信(POP3)

POP before SMTP をする際など、ちょっとした POP 認証をしておきたい時のために
単純なメール受信クラスを作ってみました。
open() でメールサーバーに接続し retrieve() で受信できます。

【注意】
このクラスは学習目的のサンプルです。
実用の際は PEAR::Net_POP3 などを利用して下さい。

・Pop3Retrieve.php

<?php
class Pop3Retrieve{
	private $connect;

	//接続
	function open($host, $user, $pass, $port=110){
		$this->connect = fsockopen( $host, $port, $err, $errno );
		if ( !$this->connect ) {
			return false;
		}
		
		fputs($this->connect, "USER {$user}\r\n");
		if(!$this->check_response()) return false;

		fputs($this->connect, "PASS {$pass}\r\n");
		if(!$this->check_response()) return false;
	}
	
	//レスポンスコード確認
	function check_response(){
		$buf = fgets($this->connect, 512);
		if( substr($buf, 0, 3) != '+OK' ) {
			return false;
		} else {
			return true;
		}
	}

	//メール数確認
	function status(){
		fputs($this->connect, "STAT\r\n");
		
		if( !$this->check_response() ) return false;
		$buf = fgets($this->connect, 512);
		sscanf($buf, '+OK %d %d', $num, $size);
		
		return $num;
	}
	
	//num番目のメールを受信
	function retrieve($num=1){
		$default_timeout = ini_get('default_socket_timeout');
		stream_set_timeout($this->connect, 3);
		
		fputs($this->connect, "RETR {$num}\r\n");

		if( !$this->check_response() ) return false;
		
		$data = "";
		$line = "";
		
		while ( !feof($this->connect) ) {
			$meta_data = stream_get_meta_data($this->connect);
			if($meta_data["timed_out"]) break;
			
			$line = fgets($this->connect);
			if($line === false || preg_match("/^\.\r\n/", $line)) break;
			$line = preg_replace("/^\.\./", ".", $line);
			$data .= $line;
		}
		
		stream_set_timeout($this->connect, $default_timeout);
		
		return $data;
	}
	
	//削除
	function delete($num=1){
		fputs($this->connect, "DELE {$num}\r\n");

		if( !$this->check_response() ) return false;
	
	}

	//終了
	function close(){
		fputs($this->connect, "QUIT\r\n");
		if( !$this->check_response() ) return false;
		
		fclose($this->connect);
	}
}

・使い方

<?php
include_once "Pop3Retrieve.php";

$host = 'tcp://mail.sample.com';
$user = 'user';
$pass = 'password';
$port = 110;

$pop3 = new Pop3Retrieve();
$pop3->open($host, $user, $pass, $port);

//総数を確認
$count = $pop3->status();

//全て受信
$mail = array();
for($i=1;$i<=$count;$i++){
	$mail[] = $pop3->retrieve($i);
}

$pop3->close();

取得されたメールはデコードされていない状態なので、
本文や件名などをパースする場合は PEAR の Mail_mimeDecode などを使うのが便利です。

POP Before SMTP 対策だけが目的であれば imap_open() 関数を使ったほうが簡単かもしれません。

$result = imap_open( sprintf('{%s:%d/pop3}INBOX', $host, $port), $user ,$pass );

サーバーによっては「/notls」フラグを追加する必要があります。

$result = imap_open( sprintf('{%s:%d/pop3/notls}INBOX', $host, $port), $user ,$pass );