PHPCap Docs | PHPCap API
Overview

Namespaces

  • IU
    • PHPCap
  • PHP

Classes

  • IU\PHPCap\ErrorHandler
  • IU\PHPCap\FileUtil
  • IU\PHPCap\RedCap
  • IU\PHPCap\RedCapApiConnection
  • IU\PHPCap\RedCapProject

Interfaces

  • IU\PHPCap\ErrorHandlerInterface
  • IU\PHPCap\RedCapApiConnectionInterface

Exceptions

  • Exception
  • IU\PHPCap\PhpCapException
  • Overview
  • Namespace
  • Class
  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:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 
<?php

/**
 * Contains class for creating and using a connection to a REDCap API.
 */

namespace IU\PHPCap;

/**
 * A connection to the API of a REDCap instance. This class provides a low-level
 * interface to the REDCap API, and is primarily intended for internal use by PHPCap,
 * but could be used directly by a user to access REDCap functionality not provided
 * by PHPCap.
 */
class RedCapApiConnection implements RedCapApiConnectionInterface
{
    const DEFAULT_TIMEOUT_IN_SECONDS = 1200; // 1,200 seconds = 20 minutes
    const DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS = 20;
    
    /** resource cURL handle. */
    private $curlHandle;
    
    /** array used to stored cURL option values. */
    private $curlOptions;

    /** the error handler for the connection. */
    protected $errorHandler;
    
    /**
     * {@inheritdoc}
     *
     * @throws PhpCapException if an error occurs and the default error handler is being used.
     */
    public function __construct(
        $url,
        $sslVerify = false,
        $caCertificateFile = '',
        $errorHandler = null
    ) {
        # If an error handler was specified, use it,
        # otherwise, use the default PHPCap error handler
        if (isset($errorHandler)) {
            $this->errorHandler = $errorHandler;
        } else {
            $this->errorHandler = new ErrorHandler();
        }
        
        $this->curlOptions = array();
        
        $this->curlHandle = curl_init();
        
        $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $sslVerify);
        $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 2);
        
        if ($sslVerify && $caCertificateFile != null && trim($caCertificateFile) != '') {
            if (! file_exists($caCertificateFile)) {
                $message = 'The cert file "'. $caCertificateFile.'" does not exist.';
                $code    = ErrorHandlerInterface::CA_CERTIFICATE_FILE_NOT_FOUND;
                $this->errorHandler->throwException($message, $code);
            } elseif (! is_readable($caCertificateFile)) {
                $message = 'The cert file "'. $caCertificateFile.'" exists, but cannot be read.';
                $code    = ErrorHandlerInterface::CA_CERTIFICATE_FILE_UNREADABLE;
                $this->errorHandler->throwException($message, $code);
            } // @codeCoverageIgnore

            $this->setCurlOption(CURLOPT_CAINFO, $caCertificateFile);
        }
        
        $this->setCurlOption(CURLOPT_TIMEOUT, self::DEFAULT_TIMEOUT_IN_SECONDS);
        $this->setCurlOption(CURLOPT_CONNECTTIMEOUT, self::DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS);
        $this->setCurlOption(CURLOPT_URL, $url);
        $this->setCurlOption(CURLOPT_RETURNTRANSFER, true);
        $this->setCurlOption(CURLOPT_HTTPHEADER, array ('Accept: text/xml'));
        $this->setCurlOption(CURLOPT_POST, 1);
    }

    /**
     * Closes the cURL handle (if it is set).
     */
    public function __destruct()
    {
        if (isset($this->curlHandle)) {
            curl_close($this->curlHandle);
            $this->curlHandle = null;
        }
    }


    public function call($data)
    {
        if (!is_string($data) && !is_array($data)) {
            $message = "Data passed to ".__METHOD__." has type ".gettype($data)
                .", but should be a string or an array.";
            $code = ErrorHandlerInterface::INVALID_ARGUMENT;
            $this->errorHandler->throwException($message, $code);
        } // @codeCoverageIgnore
        
        $errno = 0;
        $response = '';
        
        // Post specified data (and do NOT save this in the options array)
        curl_setopt($this->curlHandle, CURLOPT_POSTFIELDS, $data);
        $response = curl_exec($this->curlHandle);
        
        if ($errno = curl_errno($this->curlHandle)) {
            $message = curl_error($this->curlHandle);
            $code    = ErrorHandlerInterface::CONNECTION_ERROR;
            
            # Had one case where curl_error didn't return a message
            if ($message == null || $message == '') {
                $message = curl_strerror($errno);
                if ($message == null || $message == '') {
                    $message = 'Connection error '.$errno.' occurred.';
                }
            }
            $this->errorHandler->throwException($message, $code, $errno);
        } else { // @codeCoverageIgnore
            // Check for HTTP errors
            $httpCode = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
            if ($httpCode == 301) {
                $callInfo = curl_getinfo($this->curlHandle);
                $message =  "The page for the specified URL ("
                    .$this->getCurlOption(CURLOPT_URL). ") has moved to "
                    .$callInfo ['redirect_url'] . ". Please update your URL.";
                $code = ErrorHandlerInterface::INVALID_URL;
                $this->errorHandler->throwException($message, $code, null, $httpCode);
            } elseif ($httpCode == 404) {
                $message = 'The specified URL ('.$this->getCurlOption(CURLOPT_URL)
                    .') appears to be incorrect. Nothing was found at this URL.';
                $code = ErrorHandlerInterface::INVALID_URL;
                $this->errorHandler->throwException($message, $code, null, $httpCode);
            } // @codeCoverageIgnore
        }
        
        return ($response);
    }
    

    public function callWithArray($dataArray)
    {
        $data = http_build_query($dataArray, '', '&');
        return $this->call($data);
    }

    
    /**
     * Returns call information for the most recent call.
     *
     * @throws PhpCapException if an error occurs and the default error handler is being used.
     * @return array an associative array of values of call information for the most recent call made.
     *
     * @see <a href="http://php.net/manual/en/function.curl-getinfo.php">http://php.net/manual/en/function.curl-getinfo.php</a>
     *      for information on what values are returned.
     */
    public function getCallInfo()
    {
        $callInfo = curl_getinfo($this->curlHandle);
        if ($errno = curl_errno($this->curlHandle)) {
            $message = curl_error($this->curlHandle);
            $code    = ErrorHandlerInterface::CONNECTION_ERROR;
            $this->errorHandler->throwException($message, $code, $errno);
        } // @codeCoverageIgnore
        
        return $callInfo;
    }


    /**
     * {@inheritdoc}
     */
    public function getErrorHandler()
    {
        return $this->errorHandler;
    }
    

    public function setErrorHandler($errorHandler)
    {
        $this->errorHandler = $errorHandler;
    }
    

    public function getUrl()
    {
        return $this->getCurlOption(CURLOPT_URL);
    }
    
    public function setUrl($url)
    {
        return $this->setCurlOption(CURLOPT_URL, $url);
    }
    
    public function getSslVerify()
    {
        return $this->getCurlOption(CURLOPT_SSL_VERIFYPEER);
    }
    
    public function setSslVerify($sslVerify)
    {
        $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $sslVerify);
    }
    
    
    public function getCaCertificateFile()
    {
        return $this->getCurlOption(CURLOPT_CAINFO);
    }
    
    public function setCaCertificateFile($caCertificateFile)
    {
        $this->setCurlOption(CURLOPT_CAINFO, $caCertificateFile);
    }
    
    public function getTimeoutInSeconds()
    {
        return $this->getCurlOption(CURLOPT_TIMEOUT);
    }
    
    public function setTimeoutInSeconds($timeoutInSeconds)
    {
        $this->setCurlOption(CURLOPT_TIMEOUT, $timeoutInSeconds);
    }

    public function getConnectionTimeoutInSeconds()
    {
        return $this->getCurlOption(CURLOPT_CONNECTTIMEOUT);
    }
    
    public function setConnectionTimeoutInSeconds($connectionTimeoutInSeconds)
    {
        $this->setCurlOption(CURLOPT_CONNECTTIMEOUT, $connectionTimeoutInSeconds);
    }
    
    
    /**
     * Sets the specified cURL option to the specified value.
     *
     * {@internal
     *     NOTE: this method is cURL specific and is NOT part
     *     of the connection interface, and therefore should
     *     NOT be used internally by PHPCap outside of this class.
     * }
     *
     * @see <a href="http://php.net/manual/en/function.curl-setopt.php">http://php.net/manual/en/function.curl-setopt.php</a>
     *      for information on cURL options.
     *
     * @param integer $option the cURL option that is being set.
     * @param mixed $value the value that the cURL option is being set to.
     * @return boolean Returns true on success and false on failure.
     */
    public function setCurlOption($option, $value)
    {
        $this->curlOptions[$option] = $value;
        $result = curl_setopt($this->curlHandle, $option, $value);
        return $result;
    }

    /**
     * Gets the value for the specified cURL option number.
     *
     * {@internal
     *     NOTE: this method is cURL specific and is NOT part
     *     of the connection interface, and therefore should
     *     NOT be used internally by PHPCap outside of this class.
     * }
     *
     * @see <a href="http://php.net/manual/en/function.curl-setopt.php">http://php.net/manual/en/function.curl-setopt.php</a>
     * for information on cURL options.
     *
     * @param integer $option cURL option number.
     * @return mixed if the specified option has a value that has been set in the code,
     *     then the value is returned. If no value was set, then null is returned.
     *     Note that the cURL CURLOPT_POSTFIELDS option value is not saved,
     *     because it is reset with every call and can can be very large.
     *     As a result, null will always be returned for this cURL option.
     */
    public function getCurlOption($option)
    {
        $optionValue = null;
        if (array_key_exists($option, $this->curlOptions)) {
            $optionValue = $this->curlOptions[$option];
        }
        return $optionValue;
    }
    
    public function __clone()
    {
        # Reset the curlHandle so it will be a new handle
        $this->curlHandle = curl_init();
        
        # Reset all of the options (for the new handle)
        foreach ($this->curlOptions as $optionName => $optionValue) {
            $this->setCurlOption($optionName, $optionValue);
        }
        
        $this->errorHandler = clone $this->errorHandler;
    }
}
PHPCap API documentation generated by ApiGen