* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 * @link https://wiki.jasig.org/display/CASC/phpCAS */ /** * This interface defines a class library for performing multiple web requests * in batches. Implementations of this interface may perform requests serially * or in parallel. * * @class CAS_Request_CurlMultiRequest * @category Authentication * @package PhpCAS * @author Adam Franco * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 * @link https://wiki.jasig.org/display/CASC/phpCAS */ class CAS_Request_CurlMultiRequest implements CAS_Request_MultiRequestInterface { private $_requests = array(); private $_sent = false; /********************************************************* * Add Requests *********************************************************/ /** * Add a new Request to this batch. * Note, implementations will likely restrict requests to their own concrete * class hierarchy. * * @param CAS_Request_RequestInterface $request reqest to add * * @return void * @throws CAS_OutOfSequenceException If called after the Request has been sent. * @throws CAS_InvalidArgumentException If passed a Request of the wrong * implmentation. */ public function addRequest (CAS_Request_RequestInterface $request) { if ($this->_sent) { throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__); } if (!$request instanceof CAS_Request_CurlRequest) { throw new CAS_InvalidArgumentException('As a CAS_Request_CurlMultiRequest, I can only work with CAS_Request_CurlRequest objects.'); } $this->_requests[] = $request; } /** * Retrieve the number of requests added to this batch. * * @return number of request elements */ public function getNumRequests() { if ($this->_sent) { throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__); } return count($this->_requests); } /********************************************************* * 2. Send the Request *********************************************************/ /** * Perform the request. After sending, all requests will have their * responses poulated. * * @return bool TRUE on success, FALSE on failure. * @throws CAS_OutOfSequenceException If called multiple times. */ public function send () { if ($this->_sent) { throw new CAS_OutOfSequenceException('Request has already been sent cannot send again.'); } if (!count($this->_requests)) { throw new CAS_OutOfSequenceException('At least one request must be added via addRequest() before the multi-request can be sent.'); } $this->_sent = true; // Initialize our handles and configure all requests. $handles = array(); $multiHandle = curl_multi_init(); foreach ($this->_requests as $i => $request) { $handle = $request->_initAndConfigure(); curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); $handles[$i] = $handle; curl_multi_add_handle($multiHandle, $handle); } // Execute the requests in parallel. do { curl_multi_exec($multiHandle, $running); } while ($running > 0); // Populate all of the responses or errors back into the request objects. foreach ($this->_requests as $i => $request) { $buf = curl_multi_getcontent($handles[$i]); $request->_storeResponseBody($buf); curl_multi_remove_handle($multiHandle, $handles[$i]); curl_close($handles[$i]); } curl_multi_close($multiHandle); } }