Zend_Xmlrpcでエラー
ふつーに使おうとしたらオペランドがどうこういわれた
$client = new Zend_XmlRpc_Client('http://example.com/api/xmlrpc');
$client->call('Hogehoge.entry');
とふつーに使おうとしたら
Fatal error: Unsupported operand types in /usr/local/php/lib/php/Zend/Http/Client/Adapter/Socket.php on line 303
とか、言われることがあった。
http://example.com/api/xmlrpcがContent-lengthを2回返すサーバーだったりすると言われる。
Zend/Http/Client/Adapter/Socket.phpの当該部分をみると
while ($left_to_read > 0) { $chunk = @fread($this->socket, $left_to_read); if ($chunk === false || strlen($chunk) === 0) { break; } else { $left_to_read -= strlen($chunk); $response .= $chunk; } // Break if the connection ended prematurely if (feof($this->socket)) break; }
となっていて
$left_to_read -= strlen($chunk);
でこけてる。
$left_to_readは
$left_to_read = $headers['content-length'];
で、$headersは
$headers = Zend_Http_Response::extractHeaders($response);
で、$responseは
while (($line = @fgets($this->socket)) !== false) {
$gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false);
if ($gotStatus) {
$response .= $line;
if (rtrim($line) === '') break;
}
}
で、$this->socketは
$this->socket = @stream_socket_client($host . ':' . $port, $errno, $errstr, (int) $this->config['timeout'], $flags, $context);
Zend_Http_Response::extractHeaders($response);
で、そこのメソッドは
/** * Extract the headers from a response string * * @param string $response_str * @return array */ public static function extractHeaders($response_str) { $headers = array(); // First, split body and headers $parts = preg_split('|(?:\r?\n){2}|m', $response_str, 2); if (! $parts[0]) return $headers; // Split headers part to lines $lines = explode("\n", $parts[0]); unset($parts); $last_header = null; foreach($lines as $line) { $line = trim($line, "\r\n"); if ($line == "") break; if (preg_match("|^([\w-]+):\s+(.+)|", $line, $m)) { unset($last_header); $h_name = strtolower($m[1]); $h_value = $m[2]; if (isset($headers[$h_name])) { if (! is_array($headers[$h_name])) { $headers[$h_name] = array($headers[$h_name]); } $headers[$h_name][] = $h_value; } else { $headers[$h_name] = $h_value; } $last_header = $h_name; } elseif (preg_match("|^\s+(.+)$|", $line, $m) && $last_header !== null) { if (is_array($headers[$last_header])) { end($headers[$last_header]); $last_header_key = key($headers[$last_header]); $headers[$last_header][$last_header_key] .= $m[1]; } else { $headers[$last_header] .= $m[1]; } } } return $headers; }
なので
if (isset($headers[$h_name])) {
if (! is_array($headers[$h_name])) {
$headers[$h_name] = array($headers[$h_name]);
}
$headers[$h_name][] = $h_value;
} else {
$headers[$h_name] = $h_value;
}
から、同じ名前のやつがきたら配列として取っておくようなので
content-lengthが2行あれば
返ってくる$header['content-length']はarrayで帰ってくる
そーすると、最初の
while ($left_to_read > 0) { $chunk = @fread($this->socket, $left_to_read); if ($chunk === false || strlen($chunk) === 0) { break; } else { $left_to_read -= strlen($chunk); $response .= $chunk; } // Break if the connection ended prematurely if (feof($this->socket)) break; }
は、$left_to_read -= strlen($chunk);とあるから、配列で帰ってこないことが前提なようなので
そこでFatal error: Unsupported operand typesだといわれる。
HTTPの仕様的には
受ける方が、余計なのを無視する方が正しいのだと思っているので、Zend_Http_Responseがいけない子な気がしている。