Guest User

oauth file from linkedin

a guest
Jun 21st, 2012
121
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. if(!extension_loaded('oauth')) {
  2.   // the PECL OAuth extension is not present, load our third-party OAuth library
  3.   require_once('../LinkedIn_API_OAuth/OAuth.php');
  4. } else {
  5.   // the PECL extension is present, which is not compatible with this library
  6.   throw new LinkedInException('Simple-LinkedIn: library not compatible with installed PECL OAuth extension.  Please disable this extension to use the Simple-LinkedIn library.');
  7. }
  8.  
  9. /**
  10.  * 'LinkedInException' class declaration.
  11.  *  
  12.  * This class extends the base 'Exception' class.
  13.  *
  14.  * @access public
  15.  * @package classpackage
  16.  */
  17. class LinkedInException extends Exception {}
  18.  
  19. /**
  20.  * 'LinkedIn' class declaration.
  21.  *  
  22.  * This class provides generalized LinkedIn oauth functionality.
  23.  *
  24.  * @access public
  25.  * @package classpackage
  26.  */
  27. class LinkedIn {
  28.   // api/oauth settings
  29.   const _API_OAUTH_REALM             = 'http://api.linkedin.com';
  30.   const _API_OAUTH_VERSION           = '1.0';
  31.  
  32.   // the default response format from LinkedIn
  33.   const _DEFAULT_RESPONSE_FORMAT     = 'xml';
  34.    
  35.   // helper constants used to standardize LinkedIn <-> API communication.  See demo page for usage.
  36.   const _GET_RESPONSE                = 'lResponse';
  37.   const _GET_TYPE                    = 'lType';
  38.  
  39.   // Invitation API constants.
  40.   const _INV_SUBJECT                 = 'Invitation to connect';
  41.   const _INV_BODY_LENGTH             = 200;
  42.  
  43.   // API methods
  44.   const _METHOD_TOKENS               = 'POST';
  45.  
  46.   // Network API constants.
  47.   const _NETWORK_LENGTH              = 1000;
  48.   const _NETWORK_HTML                = '<a>';
  49.  
  50.   // response format type constants, see http://developer.linkedin.com/docs/DOC-1203
  51.   const _RESPONSE_JSON               = 'JSON';
  52.   const _RESPONSE_JSONP              = 'JSONP';
  53.   const _RESPONSE_XML                = 'XML';
  54.  
  55.   // Share API constants
  56.   const _SHARE_COMMENT_LENGTH        = 700;
  57.   const _SHARE_CONTENT_TITLE_LENGTH  = 200;
  58.   const _SHARE_CONTENT_DESC_LENGTH   = 400;
  59.  
  60.   // LinkedIn API end-points
  61.     const _URL_ACCESS                  = 'https://api.linkedin.com/uas/oauth/accessToken';
  62.     const _URL_API                     = 'https://api.linkedin.com';
  63.     const _URL_AUTH                    = 'https://www.linkedin.com/uas/oauth/authenticate?oauth_token=';
  64.     const _URL_REQUEST                 = 'https://api.linkedin.com/uas/oauth/requestToken';
  65.     const _URL_REVOKE                  = 'https://api.linkedin.com/uas/oauth/invalidateToken';
  66.    
  67.     // Library version
  68.     const _VERSION                     = '3.2.0';
  69.  
  70.   // oauth properties
  71.   protected $callback;
  72.   protected $token                   = NULL;
  73.  
  74.   // application properties
  75.   protected $application_key,
  76.             $application_secret;
  77.  
  78.   // the format of the data to return
  79.   protected $response_format         = self::_DEFAULT_RESPONSE_FORMAT;
  80.  
  81.   // last request fields
  82.   public $last_request_headers,
  83.          $last_request_url;
  84.  
  85.     /**
  86.      * Create a LinkedIn object, used for OAuth-based authentication and
  87.      * communication with the LinkedIn API.  
  88.      *
  89.      * @param arr $config
  90.      *    The 'start-up' object properties:
  91.      *           - appKey       => The application's API key
  92.      *           - appSecret    => The application's secret key
  93.      *           - callbackUrl  => [OPTIONAL] the callback URL
  94.      *                  
  95.      * @return obj
  96.      *    A new LinkedIn object.     
  97.      */
  98.     public function __construct($config) {
  99.     if(!is_array($config)) {
  100.       // bad data passed
  101.           throw new LinkedInException('LinkedIn->__construct(): bad data passed, $config must be of type array.');
  102.     }
  103.     $this->setApplicationKey($config['appKey']);
  104.       $this->setApplicationSecret($config['appSecret']);
  105.       $this->setCallbackUrl($config['callbackUrl']);
  106.     }
  107.    
  108.     /**
  109.    * The class destructor.
  110.    *
  111.    * Explicitly clears LinkedIn object from memory upon destruction.
  112.      */
  113.   public function __destruct() {
  114.     unset($this);
  115.     }
  116.    
  117.     /**
  118.      * Bookmark a job.
  119.      *
  120.      * Calling this method causes the current user to add a bookmark for the
  121.      * specified job:
  122.      *
  123.      *   http://developer.linkedin.com/docs/DOC-1323
  124.      *
  125.      * @param str $jid
  126.      *    Job ID you want to bookmark.
  127.      *          
  128.      * @return arr
  129.      *    Array containing retrieval success, LinkedIn response.
  130.      */
  131.     public function bookmarkJob($jid) {
  132.       // check passed data
  133.       if(!is_string($jid)) {
  134.         // bad data passed
  135.           throw new LinkedInException('LinkedIn->bookmarkJob(): bad data passed, $jid must be of type string.');
  136.       }
  137.      
  138.       // construct and send the request
  139.       $query    = self::_URL_API . '/v1/people/~/job-bookmarks';
  140.       $response = $this->fetch('POST', $query, '<job-bookmark><job><id>' . trim($jid) . '</id></job></job-bookmark>');
  141.      
  142.       /**
  143.        * Check for successful request (a 201 response from LinkedIn server)
  144.        * per the documentation linked in method comments above.
  145.        */
  146.         return $this->checkResponse(201, $response);
  147.     }
  148.    
  149.     /**
  150.      * Get list of jobs you have bookmarked.
  151.      *
  152.      * Returns a list of jobs the current user has bookmarked, per:
  153.      *
  154.      *   http://developer.linkedin.com/docs/DOC-1323  
  155.      *  
  156.      * @return arr
  157.      *         Array containing retrieval success, LinkedIn response.
  158.      */
  159.     public function bookmarkedJobs() { 
  160.     // construct and send the request  
  161.       $query    = self::_URL_API . '/v1/people/~/job-bookmarks';
  162.       $response = $this->fetch('GET', $query);
  163.      
  164.       /**
  165.        * Check for successful request (a 200 response from LinkedIn server)
  166.        * per the documentation linked in method comments above.
  167.        */
  168.         return $this->checkResponse(200, $response);
  169.     }
  170.    
  171.     /**
  172.      * Used to check whether a response LinkedIn object has the required http_code or not and
  173.      * returns an appropriate LinkedIn object.
  174.      *
  175.      * @param var $http_code_required
  176.      *      The required http response from LinkedIn, passed in either as an integer,
  177.      *      or an array of integers representing the expected values.    
  178.      * @param arr $response
  179.      *    An array containing a LinkedIn response.
  180.      *
  181.      * @return boolean
  182.      *    TRUE or FALSE depending on if the passed LinkedIn response matches the expected response.
  183.      */
  184.     private function checkResponse($http_code_required, $response) {
  185.         // check passed data
  186.     if(is_array($http_code_required)) {
  187.           array_walk($http_code_required, function($value, $key) {
  188.         if(!is_int($value)) {
  189.                 throw new LinkedInException('LinkedIn->checkResponse(): $http_code_required must be an integer or an array of integer values');
  190.             }
  191.       });
  192.         } else {
  193.           if(!is_int($http_code_required)) {
  194.             throw new LinkedInException('LinkedIn->checkResponse(): $http_code_required must be an integer or an array of integer values');
  195.         } else {
  196.           $http_code_required = array($http_code_required);
  197.         }
  198.         }
  199.         if(!is_array($response)) {
  200.             throw new LinkedInException('LinkedIn->checkResponse(): $response must be an array');
  201.         }      
  202.        
  203.         // check for a match
  204.         if(in_array($response['info']['http_code'], $http_code_required)) {
  205.           // response found
  206.           $response['success'] = TRUE;
  207.         } else {
  208.             // response not found
  209.             $response['success'] = FALSE;
  210.             $response['error']   = 'HTTP response from LinkedIn end-point was not code ' . implode(', ', $http_code_required);
  211.         }
  212.         return $response;
  213.     }
  214.    
  215.     /**
  216.      * Close a job.
  217.      *
  218.      * Calling this method causes the passed job to be closed, per:
  219.      *
  220.      *   http://developer.linkedin.com/docs/DOC-1151  
  221.      *
  222.      * @param str $jid
  223.      *    Job ID you want to close.
  224.      *             
  225.      * @return arr
  226.      *    Array containing retrieval success, LinkedIn response.
  227.      */
  228.     public function closeJob($jid) {
  229.       // check passed data
  230.       if(!is_string($jid)) {
  231.         // bad data passed
  232.           throw new LinkedInException('LinkedIn->closeJob(): bad data passed, $jid must be of string value.');
  233.       }
  234.      
  235.       // construct and send the request
  236.       $query    = self::_URL_API . '/v1/jobs/partner-job-id=' . trim($jid);
  237.       $response = $this->fetch('DELETE', $query);
  238.      
  239.       /**
  240.        * Check for successful request (a 204 response from LinkedIn server)
  241.        * per the documentation linked in method comments above.
  242.        */
  243.       return $this->checkResponse(204, $response);
  244.     }
  245.    
  246.     /**
  247.      * Share comment posting method.
  248.      *
  249.      * Post a comment on an existing connections shared content. API details can
  250.      * be found here:
  251.      *
  252.      * http://developer.linkedin.com/docs/DOC-1043
  253.      *
  254.      * @param str $uid
  255.      *    The LinkedIn update ID.        
  256.      * @param str $comment
  257.      *    The share comment to be posted.
  258.      *               
  259.      * @return arr
  260.      *    Array containing retrieval success, LinkedIn response.        
  261.      */
  262.     public function comment($uid, $comment) {
  263.       // check passed data
  264.       if(!is_string($uid)) {
  265.         // bad data passed
  266.           throw new LinkedInException('LinkedIn->comment(): bad data passed, $uid must be of type string.');
  267.       }
  268.     if(!is_string($comment)) {
  269.       // nothing/non-string passed, raise an exception
  270.           throw new LinkedInException('LinkedIn->comment(): bad data passed, $comment must be a non-zero length string.');
  271.     }
  272.    
  273.     /**
  274.      * Share comment rules:
  275.      *
  276.      * 1) No HTML permitted.
  277.      * 2) Comment cannot be longer than 700 characters.    
  278.      */
  279.     $comment = substr(trim(htmlspecialchars(strip_tags($comment))), 0, self::_SHARE_COMMENT_LENGTH);
  280.         $data    = '<?xml version="1.0" encoding="UTF-8"?>
  281.                 <update-comment>
  282.                         <comment>' . $comment . '</comment>
  283.                       </update-comment>';
  284.  
  285.     // construct and send the request
  286.     $query    = self::_URL_API . '/v1/people/~/network/updates/key=' . $uid . '/update-comments';
  287.     $response = $this->fetch('POST', $query, $data);
  288.    
  289.     /**
  290.        * Check for successful request (a 201 response from LinkedIn server)
  291.        * per the documentation linked in method comments above.
  292.        */
  293.     return $this->checkResponse(201, $response);
  294.     }
  295.    
  296.     /**
  297.      * Share comment retrieval.
  298.      *    
  299.      * Return all comments associated with a given network update:
  300.      *  
  301.      *   http://developer.linkedin.com/docs/DOC-1043
  302.      *
  303.      * @param str $uid
  304.      *    The LinkedIn update ID.
  305.      *                      
  306.      * @return arr
  307.      *    Array containing retrieval success, LinkedIn response.                  
  308.      */
  309.     public function comments($uid) {
  310.       // check passed data
  311.       if(!is_string($uid)) {
  312.         // bad data passed
  313.           throw new LinkedInException('LinkedIn->comments(): bad data passed, $uid must be of type string.');
  314.       }
  315.        
  316.         // construct and send the request
  317.     $query    = self::_URL_API . '/v1/people/~/network/updates/key=' . $uid . '/update-comments';
  318.     $response = $this->fetch('GET', $query);
  319.    
  320.     /**
  321.        * Check for successful request (a 200 response from LinkedIn server)
  322.        * per the documentation linked in method comments above.
  323.        */
  324.     return $this->checkResponse(200, $response);
  325.     }
  326.    
  327.     /**
  328.      * Company profile retrieval function.
  329.      *
  330.      * Takes a string of parameters as input and requests company profile data
  331.      * from the LinkedIn Company Profile API. See the official documentation for
  332.      * $options 'field selector' formatting:
  333.      *
  334.      *   http://developer.linkedin.com/docs/DOC-1014
  335.      *   http://developer.linkedin.com/docs/DOC-1259  
  336.      *
  337.      * @param str $options
  338.      *    Data retrieval options.  
  339.      * @param   bool $by_email
  340.      *    [OPTIONAL] Search by email domain?
  341.      *  
  342.      * @return arr
  343.      *    Array containing retrieval success, LinkedIn response.
  344.      */
  345.     public function company($options, $by_email = FALSE) {
  346.       // check passed data
  347.       if(!is_string($options)) {
  348.         // bad data passed
  349.           throw new LinkedInException('LinkedIn->company(): bad data passed, $options must be of type string.');
  350.       }
  351.       if(!is_bool($by_email)) {
  352.         // bad data passed
  353.           throw new LinkedInException('LinkedIn->company(): bad data passed, $by_email must be of type boolean.');
  354.       }
  355.      
  356.       // construct and send the request
  357.       $query    = self::_URL_API . '/v1/companies' . ($by_email ? '' : '/') . trim($options);
  358.       $response = $this->fetch('GET', $query);
  359.      
  360.       /**
  361.        * Check for successful request (a 200 response from LinkedIn server)
  362.        * per the documentation linked in method comments above.
  363.        */
  364.       return $this->checkResponse(200, $response);
  365.     }
  366.    
  367.   /**
  368.      * Company products and their associated recommendations.
  369.      *
  370.      * The product data type contains details about a company's product or
  371.      * service, including recommendations from LinkedIn members, and replies from
  372.      * company representatives.
  373.      *
  374.      *   http://developer.linkedin.com/docs/DOC-1327  
  375.      *
  376.      * @param str $cid
  377.      *    Company ID you want the producte for.
  378.      * @param str $options
  379.      *    [OPTIONAL] Data retrieval options.
  380.      *             
  381.      * @return arr
  382.      *    Array containing retrieval success, LinkedIn response.
  383.      */
  384.     public function companyProducts($cid, $options = '') {
  385.       // check passed data
  386.       if(!is_string($cid)) {
  387.         // bad data passed
  388.           throw new LinkedInException('LinkedIn->companyProducts(): bad data passed, $cid must be of type string.');
  389.       }
  390.       if(!is_string($options)) {
  391.         // bad data passed
  392.           throw new LinkedInException('LinkedIn->companyProducts(): bad data passed, $options must be of type string.');
  393.       }
  394.      
  395.       // construct and send the request
  396.       $query    = self::_URL_API . '/v1/companies/' . trim($cid) . '/products' . trim($options);
  397.       $response = $this->fetch('GET', $query);
  398.      
  399.       /**
  400.        * Check for successful request (a 200 response from LinkedIn server)
  401.        * per the documentation linked in method comments above.
  402.        */
  403.       return $this->checkResponse(200, $response);
  404.     }
  405.    
  406.     /**
  407.      * Connection retrieval function.
  408.      *
  409.      * Takes a string of parameters as input and requests connection-related data
  410.      * from the Linkedin Connections API. See the official documentation for
  411.      * $options 'field selector' formatting:
  412.      *
  413.      *   http://developer.linkedin.com/docs/DOC-1014         
  414.      *
  415.      * @param str $options
  416.      *    [OPTIONAL] Data retrieval options.
  417.      *               
  418.      * @return arr
  419.      *    Array containing retrieval success, LinkedIn response.
  420.      */
  421.     public function connections($options = '~/connections') {
  422.       // check passed data
  423.       if(!is_string($options)) {
  424.         // bad data passed
  425.           throw new LinkedInException('LinkedIn->connections(): bad data passed, $options must be of type string.');
  426.       }
  427.      
  428.       // construct and send the request
  429.       $query    = self::_URL_API . '/v1/people/' . trim($options);
  430.       $response = $this->fetch('GET', $query);
  431.      
  432.       /**
  433.        * Check for successful request (a 200 response from LinkedIn server)
  434.        * per the documentation linked in method comments above.
  435.        */
  436.       return $this->checkResponse(200, $response);
  437.     }
  438.    
  439.     /**
  440.      * This creates a post in the specified group with the specified title and specified summary.
  441.      *
  442.      *   http://developer.linkedin.com/documents/groups-api
  443.      *
  444.      * @param str $gid
  445.      *      The group id.
  446.      * @param str $title
  447.      *      The title of the post. This must be non-empty.
  448.      * @param str $summary
  449.      *      [OPTIONAL] The content or summary of the post. This can be empty.
  450.      *
  451.      * @return arr
  452.      *      Array containing retrieval success, LinkedIn response.
  453.      */
  454.     public function createPost($gid, $title, $summary = '') {
  455.         if(!is_string($gid)) {
  456.             throw new LinkedInException('LinkedIn->createPost(): bad data passed, $gid must be of type string.');
  457.         }
  458.         if(!is_string($title) || empty($title)) {
  459.             throw new LinkedInException('LinkedIn->createPost(): bad data passed, $title must be a non-empty string.');
  460.         }
  461.         if(!is_string($summary)) {
  462.             throw new LinkedInException('LinkedIn->createPost(): bad data passed, $summary must be of type string.');
  463.         }
  464.        
  465.         // construct the XML
  466.         $data = '<?xml version="1.0" encoding="UTF-8"?>
  467.                      <post>
  468.                          <title>'. $title . '</title>
  469.                          <summary>' . $summary . '</summary>
  470.                      </post>';
  471.        
  472.         // construct and send the request
  473.         $query    = self::_URL_API . '/v1/groups/' . trim($gid) . '/posts';
  474.         $response = $this->fetch('POST', $query, $data);
  475.        
  476.       /**
  477.        * Check for successful request (a 201 response from LinkedIn server)
  478.        * per the documentation linked in method comments above.
  479.        */
  480.         return $this->checkResponse(201, $response);
  481.     }
  482.    
  483.     /**
  484.      * This deletes the specified post if you are the owner or moderator that post.
  485.      * Otherwise, it just flags the post as inappropriate.
  486.      *
  487.      * https://developer.linkedin.com/documents/groups-api
  488.      *
  489.      * @param str $pid
  490.      *      The post id.
  491.      *
  492.      * @return arr
  493.      *      Array containing retrieval success, LinkedIn response.
  494.      */
  495.     public function deletePost($pid) {
  496.         if(!is_string($pid)) {
  497.             throw new LinkedInException('LinkedIn->deletePost(): bad data passed, $pid must be of type string');
  498.         }
  499.        
  500.         // construct and send the request
  501.         $query    = self::_URL_API . '/v1/posts/' . trim($pid);
  502.         $response = $this->fetch('DELETE', $query);
  503.        
  504.     /**
  505.      * Check for successful request (a 204 response from LinkedIn server)
  506.        * per the documentation linked in method comments above.
  507.        */
  508.         return $this->checkResponse(204, $response);
  509.     }
  510.    
  511.     /**
  512.      * Edit a job.
  513.      *
  514.      * Calling this method causes the passed job to be edited, with the passed
  515.      * XML instructing which fields to change, per:
  516.      *
  517.      *   http://developer.linkedin.com/docs/DOC-1154
  518.      *   http://developer.linkedin.com/docs/DOC-1142      
  519.      *
  520.      * @param str $jid
  521.      *    Job ID you want to renew.
  522.      * @param str $xml
  523.      *    The XML containing the job fields to edit.     
  524.      *             
  525.      * @return arr
  526.      *    Array containing retrieval success, LinkedIn response.
  527.      */
  528.     public function editJob($jid, $xml) {
  529.       // check passed data
  530.       if(!is_string($jid)) {
  531.         // bad data passed
  532.           throw new LinkedInException('LinkedIn->editJob(): bad data passed, $jid must be of string value.');
  533.       }
  534.       if(is_string($xml)) {
  535.         $xml = trim(stripslashes($xml));
  536.       } else {
  537.         // bad data passed
  538.           throw new LinkedInException('LinkedIn->editJob(): bad data passed, $xml must be of string value.');
  539.       }
  540.                
  541.       // construct and send the request
  542.       $query    = self::_URL_API . '/v1/jobs/partner-job-id=' . trim($jid);
  543.       $response = $this->fetch('PUT', $query, $xml);
  544.      
  545.       /**
  546.        * Check for successful request (a 200 response from LinkedIn server)
  547.        * per the documentation linked in method comments above.
  548.        */
  549.       return $this->checkResponse(200, $response);
  550.     }
  551.    
  552.     /**
  553.      * General data send/request method.
  554.      *
  555.      * @param str $method
  556.      *    The data communication method.     
  557.      * @param str $url
  558.      *    The Linkedin API endpoint to connect with.
  559.      * @param str $data
  560.      *    [OPTIONAL] The data to send to LinkedIn.
  561.      * @param arr $parameters
  562.      *    [OPTIONAL] Addition OAuth parameters to send to LinkedIn.
  563.      *        
  564.      * @return arr
  565.      *    Array containing:
  566.      *
  567.      *           array(
  568.      *             'info'      =>   Connection information,
  569.      *             'linkedin'  => LinkedIn response,  
  570.      *             'oauth'     => The OAuth request string that was sent to LinkedIn     
  571.      *           )   
  572.      */
  573.     protected function fetch($method, $url, $data = NULL, $parameters = array()) {
  574.       // check for cURL
  575.       if(!extension_loaded('curl')) {
  576.         // cURL not present
  577.       throw new LinkedInException('LinkedIn->fetch(): PHP cURL extension does not appear to be loaded/present.');
  578.       }
  579.      
  580.     try {
  581.         // generate OAuth values
  582.         $oauth_consumer  = new OAuthConsumer($this->getApplicationKey(), $this->getApplicationSecret(), $this->getCallbackUrl());
  583.         $oauth_token     = $this->getToken();
  584.         $oauth_token     = (!is_null($oauth_token)) ? new OAuthToken($oauth_token['oauth_token'], $oauth_token['oauth_token_secret']) : NULL;
  585.       $defaults        = array(
  586.         'oauth_version' => self::_API_OAUTH_VERSION
  587.       );
  588.         $parameters    = array_merge($defaults, $parameters);
  589.        
  590.         // generate OAuth request
  591.         $oauth_req = OAuthRequest::from_consumer_and_token($oauth_consumer, $oauth_token, $method, $url, $parameters);
  592.       $oauth_req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $oauth_consumer, $oauth_token);
  593.      
  594.       // start cURL, checking for a successful initiation
  595.       if(!$handle = curl_init()) {
  596.          // cURL failed to start
  597.         throw new LinkedInException('LinkedIn->fetch(): cURL did not initialize properly.');
  598.       }
  599.      
  600.       // set cURL options, based on parameters passed
  601.         curl_setopt($handle, CURLOPT_CUSTOMREQUEST, $method);
  602.       curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE);
  603.       curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE);
  604.       curl_setopt($handle, CURLOPT_URL, $url);
  605.       curl_setopt($handle, CURLOPT_VERBOSE, FALSE);
  606.      
  607.       // configure the header we are sending to LinkedIn - http://developer.linkedin.com/docs/DOC-1203
  608.       $header = array($oauth_req->to_header(self::_API_OAUTH_REALM));
  609.       if(is_null($data)) {
  610.         // not sending data, identify the content type
  611.         $header[] = 'Content-Type: text/plain; charset=UTF-8';
  612.         switch($this->getResponseFormat()) {
  613.           case self::_RESPONSE_JSON:
  614.             $header[] = 'x-li-format: json';
  615.             break;
  616.           case self::_RESPONSE_JSONP:
  617.             $header[] = 'x-li-format: jsonp';
  618.             break;
  619.         }
  620.       } else {
  621.         $header[] = 'Content-Type: text/xml; charset=UTF-8';
  622.         curl_setopt($handle, CURLOPT_POSTFIELDS, $data);
  623.       }
  624.       curl_setopt($handle, CURLOPT_HTTPHEADER, $header);
  625.    
  626.       // set the last url, headers
  627.       $this->last_request_url = $url;
  628.       $this->last_request_headers = $header;
  629.      
  630.       // gather the response
  631.       $return_data['linkedin']        = curl_exec($handle);
  632.       $return_data['info']            = curl_getinfo($handle);
  633.       $return_data['oauth']['header'] = $oauth_req->to_header(self::_API_OAUTH_REALM);
  634.       $return_data['oauth']['string'] = $oauth_req->base_string;
  635.            
  636.       // check for throttling
  637.       if(self::isThrottled($return_data['linkedin'])) {
  638.         throw new LinkedInException('LinkedIn->fetch(): throttling limit for this user/application has been reached for LinkedIn resource - ' . $url);
  639.       }
  640.      
  641.       //TODO - add check for NO response (http_code = 0) from cURL
  642.      
  643.       // close cURL connection
  644.       curl_close($handle);
  645.      
  646.       // no exceptions thrown, return the data
  647.       return $return_data;
  648.     } catch(OAuthException $e) {
  649.       // oauth exception raised
  650.       throw new LinkedInException('OAuth exception caught: ' . $e->getMessage());
  651.     }
  652.     }
  653.    
  654.     /**
  655.      * This flags a specified post as specified by type.
  656.      *
  657.      *   http://developer.linkedin.com/documents/groups-api
  658.      *
  659.      * @param str $pid
  660.      *      The post id.
  661.      * @param str $type
  662.      *      The type to flag the post as.
  663.      *
  664.      * @return arr
  665.      *      Array containing retrieval success, LinkedIn response.
  666.      */
  667.     public function flagPost($pid, $type) {
  668.         if(!is_string($pid)) {
  669.             throw new LinkedInException('LinkedIn->flagPost(): bad data passed, $pid must be of type string');
  670.         }
  671.         if(!is_string($type)) {
  672.             throw new LinkedInException('LinkedIn->flagPost(): bad data passed, $like must be of type string');
  673.         }
  674.         //Constructing the xml
  675.         $data = '<?xml version="1.0" encoding="UTF-8"?>';
  676.         switch($type) {
  677.             case 'promotion':
  678.                 $data .= '<code>promotion</code>';
  679.                 break;
  680.             case 'job':
  681.                 $data .= '<code>job</code>';
  682.                 break;
  683.             default:
  684.                 throw new LinkedInException('LinkedIn->flagPost(): invalid value for $type, must be one of: "promotion", "job"');
  685.                 break; 
  686.         }
  687.        
  688.         // construct and send the request
  689.         $query    = self::_URL_API . '/v1/posts/' . $pid . '/category/code';
  690.         $response = $this->fetch('PUT', $query, $data);
  691.          
  692.     /**
  693.      * Check for successful request (a 204 response from LinkedIn server)
  694.        * per the documentation linked in method comments above.
  695.        */
  696.         return $this->checkResponse(204, $response);
  697.     }
  698.    
  699.     /**
  700.      * Follow a company.
  701.      *
  702.      * Calling this method causes the current user to start following the
  703.      * specified company, per:
  704.      *
  705.      *   http://developer.linkedin.com/docs/DOC-1324
  706.      *
  707.      * @param str $cid
  708.      *    Company ID you want to follow.
  709.      *          
  710.      * @return arr
  711.      *    Array containing retrieval success, LinkedIn response.
  712.      */
  713.     public function followCompany($cid) {
  714.       // check passed data
  715.       if(!is_string($cid)) {
  716.         // bad data passed
  717.           throw new LinkedInException('LinkedIn->followCompany(): bad data passed, $cid must be of type string.');
  718.       }
  719.      
  720.       // construct and send the request
  721.       $query    = self::_URL_API . '/v1/people/~/following/companies';
  722.       $response = $this->fetch('POST', $query, '<company><id>' . trim($cid) . '</id></company>');
  723.      
  724.       /**
  725.        * Check for successful request (a 201 response from LinkedIn server)
  726.        * per the documentation linked in method comments above.
  727.        */
  728.       return $this->checkResponse(201, $response);
  729.     }
  730.    
  731.     /**
  732.      * Follows/Unfollows the specified post.
  733.      *
  734.      * https://developer.linkedin.com/documents/groups-api
  735.      *
  736.      * @param str $pid
  737.      *      The post id.
  738.      * @param bool $follow
  739.      *      Determines whether to follow or unfollow the post. TRUE = follow, FALSE = unfollow
  740.      *
  741.      * @return arr
  742.      *      Array containing retrieval success, LinkedIn response.
  743.      */
  744.    
  745.     public function followPost($pid, $follow) {
  746.         if(!is_string($pid)) {
  747.             throw new LinkedInException('LinkedIn->followPost(): bad data passed, $pid must be of type string');
  748.         }
  749.         if(!($follow === TRUE || $follow === FALSE)) {
  750.             throw new LinkedInException('LinkedIn->followPost(): bad data passed, $follow must be of type boolean');
  751.         }
  752.        
  753.         // construct the XML
  754.         $data = '<?xml version="1.0" encoding="UTF-8"?>
  755.                      <is-following>'. (($follow) ? 'true' : 'false'). '</is-following>';
  756.        
  757.         // construct and send the request
  758.         $query    = self::_URL_API . '/v1/posts/' . trim($pid) . '/relation-to-viewer/is-following';
  759.         $response = $this->fetch('PUT', $query, $data);
  760.        
  761.         /**
  762.        * Check for successful request (a 204 response from LinkedIn server)
  763.        * per the documentation linked in method comments above.
  764.        */
  765.         return $this->checkResponse(204, $response);
  766.     }
  767.    
  768.     /**
  769.      * Get list of companies you follow.
  770.      *
  771.      * Returns a list of companies the current user is currently following, per:
  772.      *
  773.      *   http://developer.linkedin.com/docs/DOC-1324  
  774.      *  
  775.      * @return arr
  776.      *    Array containing retrieval success, LinkedIn response.
  777.      */
  778.     public function followedCompanies() {    
  779.       // construct and send the request
  780.     $query    = self::_URL_API . '/v1/people/~/following/companies';
  781.       $response = $this->fetch('GET', $query);
  782.      
  783.       /**
  784.        * Check for successful request (a 200 response from LinkedIn server)
  785.        * per the documentation linked in method comments above.
  786.        */
  787.       return $this->checkResponse(200, $response);
  788.     }
  789.    
  790.     /**
  791.      * Get the application_key property.
  792.      *
  793.      * @return str
  794.      *    The application key.          
  795.      */
  796.     public function getApplicationKey() {
  797.       return $this->application_key;
  798.     }
  799.    
  800.     /**
  801.      * Get the application_secret property.
  802.      *
  803.      * @return str
  804.      *    The application secret.            
  805.      */
  806.     public function getApplicationSecret() {
  807.       return $this->application_secret;
  808.     }
  809.    
  810.     /**
  811.      * Get the callback property.
  812.      *
  813.      * @return str
  814.      *    The callback url.          
  815.      */
  816.     public function getCallbackUrl() {
  817.       return $this->callback;
  818.     }
  819.  
  820.   /**
  821.      * Get the response_format property.
  822.      *
  823.      * @return str
  824.      *    The response format.          
  825.      */
  826.     public function getResponseFormat() {
  827.       return $this->response_format;
  828.     }
  829.    
  830.     /**
  831.      * Get the token_access property.
  832.      *
  833.      * @return arr
  834.      *    The access token.          
  835.      */
  836.     public function getToken() {
  837.       return $this->token;
  838.     }
  839.    
  840.     /**
  841.      * [DEPRECATED] Get the token_access property.
  842.      *
  843.      * @return arr
  844.      *    The access token.          
  845.      */
  846.     public function getTokenAccess() {
  847.       return $this->getToken();
  848.     }
  849.    
  850.     /**
  851.      *
  852.      * Get information about a specific group.
  853.      *
  854.      *   http://developer.linkedin.com/documents/groups-api
  855.      *
  856.      * @param str $gid
  857.      *      The group id.
  858.      *  
  859.      * @param str $options
  860.      *      [OPTIONAL] Field selectors for the group.
  861.      *
  862.      * @return arr
  863.      *      Array containing retrieval success, LinkedIn response.
  864.      */
  865.    
  866.     public function group($gid, $options = '') {
  867.         if(!is_string($gid)){
  868.             throw new LinkedInException('LinkedIn->group(): bad data passed, $gid must be of type string.');
  869.         }
  870.         if(!is_string($options)) {
  871.             throw new LinkedInException('LinkedIn->group(): bad data passed, $options must be of type string');
  872.         }
  873.    
  874.         // construct and send the request
  875.         $query    = self::_URL_API . '/v1/groups/' . trim($gid) . trim($options);
  876.         $response = $this->fetch('GET', $query);
  877.        
  878.         /**
  879.        * Check for successful request (a 200 response from LinkedIn server)
  880.        * per the documentation linked in method comments above.
  881.        */
  882.         return $this->checkResponse(200, $response);
  883.     }
  884.    
  885.     /**
  886.      * This returns all the groups the user is a member of.
  887.      *
  888.      *   http://developer.linkedin.com/documents/groups-api
  889.      *
  890.      * @param str $options
  891.      *      [OPTIONAL] Field selectors for the groups.
  892.      *
  893.      * @return arr
  894.      *      Array containing retrieval success, LinkedIn response.
  895.      */
  896.     public function groupMemberships($options = '') {
  897.         if(!is_string($options)) {
  898.             throw new LinkedInException('LinkedIn->groupMemberships(): bad data passed, $options must be of type string');
  899.         }
  900.        
  901.         // construct and send the request
  902.         $query    = self::_URL_API . '/v1/people/~/group-memberships' . trim($options) . '?membership-state=member';
  903.         $response = $this->fetch('GET', $query);
  904.        
  905.         /**
  906.        * Check for successful request (a 200 response from LinkedIn server)
  907.        * per the documentation linked in method comments above.
  908.        */
  909.         return $this->checkResponse(200, $response);
  910.     }
  911.    
  912.     /**
  913.      * This gets a specified post made within a group.
  914.      *
  915.      *   http://developer.linkedin.com/documents/groups-api
  916.      *
  917.      * @param str $pid
  918.      *      The post id.
  919.      * @param str $options
  920.      *      [OPTIONAL] Field selectors for the post.
  921.      *
  922.      * @return arr
  923.      *      Array containing retrieval success, LinkedIn response.
  924.      */
  925.     public function groupPost($pid, $options = '') {
  926.         if(!is_string($pid)) {
  927.             throw new LinkedInException('LinkedIn->groupPost(): bad data passed, $pid must be of type string.');
  928.         }
  929.         if(!is_string($options)) {
  930.             throw new LinkedInException('LinkedIn->groupPost(): bad data passed, $options must be of type string.');
  931.         }
  932.        
  933.         // construct and send the request
  934.         $query    = self::_URL_API . '/v1/posts/' . trim($pid) . trim($options);
  935.         $response = $this->fetch('GET', $query);
  936.        
  937.         /**
  938.        * Check for successful request (a 200 response from LinkedIn server)
  939.        * per the documentation linked in method comments above.
  940.        */
  941.         return $this->checkResponse(200, $response);
  942.     }
  943.    
  944.     /**
  945.      * This returns all the comments made on the specified post within a group.
  946.      *
  947.      *   http://developer.linkedin.com/documents/groups-api
  948.      *
  949.      * @param str $pid
  950.      *      The post id.
  951.      * @param str $options
  952.      *      [OPTIONAL] Field selectors for the post comments.
  953.      *
  954.      * @return arr
  955.      *      Array containing retrieval success, LinkedIn response.
  956.      */
  957.     public function groupPostComments($pid, $options = ''){
  958.         if(!is_string($pid)){
  959.             throw new LinkedInException('LinkedIn->groupPostComments(): bad data passed, $pid must be of type string.');
  960.         }
  961.         if(!is_string($options)) {
  962.             throw new LinkedInException('LinkedIn->groupPostComments(): bad data passed, $options must be of type string.');
  963.         }      
  964.        
  965.         // construct and send the request
  966.         $query    = self::_URL_API . '/v1/posts/' . trim($pid) . '/comments' . trim($options);
  967.         $response = $this->fetch('GET', $query);
  968.  
  969.         /**
  970.        * Check for successful request (a 200 response from LinkedIn server)
  971.        * per the documentation linked in method comments above.
  972.        */
  973.         return $this->checkResponse(200, $response);
  974.     }
  975.    
  976.     /**
  977.      * This returns all the posts within a group.
  978.      *
  979.      *   http://developer.linkedin.com/documents/groups-api
  980.      *
  981.      * @param str $gid
  982.      *      The group id.
  983.      *
  984.      * @return arr
  985.      *      Array containing retrieval success, LinkedIn response.
  986.      */
  987.     public function groupPosts($gid, $options = '') {
  988.         if(!is_string($gid)){
  989.             throw new LinkedInException('LinkedIn->groupPosts(): bad data passed, $gid must be of type string');
  990.         }
  991.         if(!is_string($options)){
  992.             throw new LinkedInException('LinkedIn->groupPosts(): bad data passed, $options must be of type string');
  993.         }
  994.        
  995.         // construct and send the request
  996.         $query    = self::_URL_API . '/v1/groups/' . trim($gid)  .'/posts' . trim($options);
  997.         $response = $this->fetch('GET', $query);
  998.        
  999.         /**
  1000.        * Check for successful request (a 200 response from LinkedIn server)
  1001.        * per the documentation linked in method comments above.
  1002.        */
  1003.         return $this->checkResponse(200, $response);
  1004.     }
  1005.    
  1006.     /**
  1007.      * This returns the group settings of the specified group
  1008.      *
  1009.      *   http://developer.linkedin.com/documents/groups-api
  1010.      *
  1011.      * @param str $gid
  1012.      *      The group id.
  1013.      * @param str $options
  1014.      *      [OPTIONAL] Field selectors for the group.
  1015.      *
  1016.      * @return arr
  1017.      *      Array containing retrieval success, LinkedIn response.
  1018.      */
  1019.     public function groupSettings($gid, $options = '') {
  1020.         if(!is_string($gid)) {
  1021.             throw new LinkedInException('LinkedIn->groupSettings(): bad data passed, $gid must be of type string');
  1022.         }
  1023.         if(!is_string($options)) {
  1024.             throw new LinkedInException('LinkedIn->groupSettings(): bad data passed, $options must be of type string');
  1025.         }
  1026.        
  1027.         // construct and send the request
  1028.         $query    = self::_URL_API . '/v1/people/~/group-memberships/' . trim($gid) . trim($options);
  1029.         $response = $this->fetch('GET', $query);
  1030.        
  1031.         /**
  1032.        * Check for successful request (a 200 response from LinkedIn server)
  1033.        * per the documentation linked in method comments above.
  1034.        */
  1035.         return $this->checkResponse(200, $response);
  1036.     }
  1037.    
  1038.     /**
  1039.      * Send connection invitations.
  1040.      *    
  1041.      * Send an invitation to connect to your network, either by email address or
  1042.      * by LinkedIn ID. Details on the API here:
  1043.      *
  1044.      *   http://developer.linkedin.com/docs/DOC-1012
  1045.      *
  1046.      * @param str $method
  1047.      *    The invitation method to process.  
  1048.      * @param str $recipient
  1049.      *    The email/id to send the invitation to.        
  1050.      * @param str $subject
  1051.      *    The subject of the invitation to send.
  1052.      * @param str $body
  1053.      *    The body of the invitation to send.
  1054.      * @param str $type
  1055.      *    [OPTIONAL] The invitation request type (only friend is supported at this time by the Invite API).
  1056.      *
  1057.      * @return arr
  1058.      *    Array containing retrieval success, LinkedIn response.     
  1059.      */
  1060.     public function invite($method, $recipient, $subject, $body, $type = 'friend') {
  1061.     /**
  1062.      * Clean up the passed data per these rules:
  1063.      *
  1064.      * 1) Message must be sent to one recipient (only a single recipient permitted for the Invitation API)
  1065.      * 2) No HTML permitted
  1066.      * 3) 200 characters max in the invitation subject
  1067.      * 4) Only able to connect as a friend at this point    
  1068.      */
  1069.     // check passed data
  1070.     if(empty($recipient)) {
  1071.         throw new LinkedInException('LinkedIn->invite(): you must provide an invitation recipient.');
  1072.     }
  1073.     switch($method) {
  1074.       case 'email':
  1075.         if(is_array($recipient)) {
  1076.           $recipient = array_map('trim', $recipient);
  1077.         } else {
  1078.           // bad format for recipient for email method
  1079.           throw new LinkedInException('LinkedIn->invite(): invitation recipient email/name array is malformed.');
  1080.         }
  1081.         break;
  1082.       case 'id':
  1083.         $recipient = trim($recipient);
  1084.         if(!self::isId($recipient)) {
  1085.           // bad format for recipient for id method
  1086.           throw new LinkedInException('LinkedIn->invite(): invitation recipient ID does not match LinkedIn format.');
  1087.         }
  1088.         break;
  1089.       default:
  1090.         throw new LinkedInException('LinkedIn->invite(): bad invitation method, must be one of: email, id.');
  1091.         break;
  1092.     }
  1093.     if(!empty($subject)) {
  1094.       $subject = trim(htmlspecialchars(strip_tags(stripslashes($subject))));
  1095.     } else {
  1096.       throw new LinkedInException('LinkedIn->invite(): message subject is empty.');
  1097.     }
  1098.     if(!empty($body)) {
  1099.       $body = trim(htmlspecialchars(strip_tags(stripslashes($body))));
  1100.       if(strlen($body) > self::_INV_BODY_LENGTH) {
  1101.         throw new LinkedInException('LinkedIn->invite(): message body length is too long - max length is ' . self::_INV_BODY_LENGTH . ' characters.');
  1102.       }
  1103.     } else {
  1104.       throw new LinkedInException('LinkedIn->invite(): message body is empty.');
  1105.     }
  1106.     switch($type) {
  1107.       case 'friend':
  1108.         break;
  1109.       default:
  1110.         throw new LinkedInException('LinkedIn->invite(): bad invitation type, must be one of: friend.');
  1111.         break;
  1112.     }
  1113.    
  1114.     // construct the xml data
  1115.         $data   = '<?xml version="1.0" encoding="UTF-8"?>
  1116.                    <mailbox-item>
  1117.                      <recipients>
  1118.                    <recipient>';
  1119.                      switch($method) {
  1120.                        case 'email':
  1121.                          // email-based invitation
  1122.                          $data .= '<person path="/people/email=' . $recipient['email'] . '">
  1123.                                      <first-name>' . htmlspecialchars($recipient['first-name']) . '</first-name>
  1124.                                      <last-name>' . htmlspecialchars($recipient['last-name']) . '</last-name>
  1125.                                    </person>';
  1126.                          break;
  1127.                        case 'id':
  1128.                          // id-based invitation
  1129.                          $data .= '<person path="/people/id=' . $recipient . '"/>';
  1130.                          break;
  1131.                      }
  1132.     $data  .= '    </recipient>
  1133.                  </recipients>
  1134.                  <subject>' . $subject . '</subject>
  1135.                  <body>' . $body . '</body>
  1136.                  <item-content>
  1137.                    <invitation-request>
  1138.                      <connect-type>';
  1139.                        switch($type) {
  1140.                          case 'friend':
  1141.                            $data .= 'friend';
  1142.                            break;
  1143.                        }
  1144.     $data  .= '      </connect-type>';
  1145.                      switch($method) {
  1146.                        case 'id':
  1147.                          // id-based invitation, we need to get the authorization information
  1148.                          $query                 = 'id=' . $recipient . ':(api-standard-profile-request)';
  1149.                          $response              = self::profile($query);
  1150.                          if($response['info']['http_code'] == 200) {
  1151.                            $response['linkedin'] = self::xmlToArray($response['linkedin']);
  1152.                            if($response['linkedin'] === FALSE) {
  1153.                              // bad XML data
  1154.                              throw new LinkedInException('LinkedIn->invite(): LinkedIn returned bad XML data.');
  1155.                            }
  1156.                            $authentication = explode(':', $response['linkedin']['person']['children']['api-standard-profile-request']['children']['headers']['children']['http-header']['children']['value']['content']);
  1157.                            
  1158.                            // complete the xml        
  1159.                            $data .= '<authorization>
  1160.                                        <name>' . $authentication[0] . '</name>
  1161.                                        <value>' . $authentication[1] . '</value>
  1162.                                      </authorization>';
  1163.                          } else {
  1164.                            // bad response from the profile request, not a valid ID?
  1165.                            throw new LinkedInException('LinkedIn->invite(): could not send invitation, LinkedIn says: ' . print_r($response['linkedin'], TRUE));
  1166.                          }
  1167.                          break;
  1168.                      }
  1169.     $data  .= '    </invitation-request>
  1170.                  </item-content>
  1171.                </mailbox-item>';
  1172.    
  1173.     // send request
  1174.     $query    = self::_URL_API . '/v1/people/~/mailbox';
  1175.     $response = $this->fetch('POST', $query, $data);
  1176.        
  1177.         /**
  1178.        * Check for successful request (a 201 response from LinkedIn server)
  1179.        * per the documentation linked in method comments above.
  1180.        */
  1181.     return $this->checkResponse(201, $response);
  1182.     }
  1183.    
  1184.     /**
  1185.      * LinkedIn ID validation.
  1186.      *   
  1187.      * Checks the passed string $id to see if it has a valid LinkedIn ID format,
  1188.      * which is, as of October 15th, 2010:
  1189.      *
  1190.      *   10 alpha-numeric mixed-case characters, plus underscores and dashes.            
  1191.      *
  1192.      * @param str $id
  1193.      *    A possible LinkedIn ID.            
  1194.      *
  1195.      * @return bool
  1196.      *    TRUE/FALSE depending on valid ID format determination.                  
  1197.      */
  1198.     public static function isId($id) {
  1199.       // check passed data
  1200.     if(!is_string($id)) {
  1201.         // bad data passed
  1202.         throw new LinkedInException('LinkedIn->isId(): bad data passed, $id must be of type string.');
  1203.       }
  1204.      
  1205.       $pattern = '/^[a-z0-9_\-]{10}$/i';
  1206.       if($match = preg_match($pattern, $id)) {
  1207.         // we have a match
  1208.         $return_data = TRUE;
  1209.       } else {
  1210.         // no match
  1211.         $return_data = FALSE;
  1212.       }
  1213.       return $return_data;
  1214.     }
  1215.    
  1216.     /**
  1217.      * Throttling check.
  1218.      *
  1219.      * Checks the passed LinkedIn response to see if we have hit a throttling
  1220.      * limit:
  1221.      *
  1222.      * http://developer.linkedin.com/docs/DOC-1112
  1223.      *
  1224.      * @param arr $response
  1225.      *    The LinkedIn response.
  1226.      *                      
  1227.      * @return bool
  1228.      *    TRUE/FALSE depending on content of response.                  
  1229.      */
  1230.     public static function isThrottled($response) {
  1231.       $return_data = FALSE;
  1232.    
  1233.     // check the variable
  1234.       if(!empty($response) && is_string($response)) {
  1235.         // we have an array and have a properly formatted LinkedIn response
  1236.            
  1237.       // store the response in a temp variable
  1238.       $temp_response = self::xmlToArray($response);
  1239.       if($temp_response !== FALSE) {
  1240.           // check to see if we have an error
  1241.           if(array_key_exists('error', $temp_response) && ($temp_response['error']['children']['status']['content'] == 403) && preg_match('/throttle/i', $temp_response['error']['children']['message']['content'])) {
  1242.             // we have an error, it is 403 and we have hit a throttle limit
  1243.           $return_data = TRUE;
  1244.           }
  1245.       }
  1246.     }
  1247.     return $return_data;
  1248.     }
  1249.    
  1250.     /**
  1251.      * Job posting detail info retrieval function.
  1252.      *
  1253.      * The Jobs API returns detailed information about job postings on LinkedIn.
  1254.      * Find the job summary, description, location, and apply our professional graph
  1255.      * to present the relationship between the current member and the job poster or
  1256.      * hiring manager.
  1257.      *
  1258.      *   http://developer.linkedin.com/docs/DOC-1322  
  1259.      *
  1260.      * @param   str $jid
  1261.      *    ID of the job you want to look up.
  1262.      * @param str $options
  1263.      *    [OPTIONAL] Data retrieval options.
  1264.      *             
  1265.      * @return arr
  1266.      *    Array containing retrieval success, LinkedIn response.
  1267.      */
  1268.     public function job($jid, $options = '') {
  1269.       // check passed data
  1270.       if(!is_string($jid)) {
  1271.         // bad data passed
  1272.           throw new LinkedInException('LinkedIn->job(): bad data passed, $jid must be of type string.');
  1273.       }
  1274.       if(!is_string($options)) {
  1275.         // bad data passed
  1276.           throw new LinkedInException('LinkedIn->job(): bad data passed, $options must be of type string.');
  1277.       }
  1278.      
  1279.       // construct and send the request
  1280.       $query    = self::_URL_API . '/v1/jobs/' . trim($jid) . trim($options);
  1281.       $response = $this->fetch('GET', $query);
  1282.      
  1283.       /**
  1284.        * Check for successful request (a 200 response from LinkedIn server)
  1285.        * per the documentation linked in method comments above.
  1286.        */
  1287.       return $this->checkResponse(200, $response);
  1288.     }
  1289.    
  1290.     /**
  1291.      * Join the specified group, per:
  1292.      *
  1293.      *   http://developer.linkedin.com/documents/groups-api
  1294.      *
  1295.      * @param str $gid
  1296.      *      The group id.
  1297.      *
  1298.      * @return arr
  1299.      *      Array containing retrieval success, LinkedIn response.      
  1300.      */
  1301.     public function joinGroup($gid) {
  1302.         if(!is_string($gid)) {
  1303.             throw new LinkedInException('LinkedIn->joinGroup(): bad data passed, $gid must be of type string.');
  1304.         }
  1305.        
  1306.         // constructing the XML
  1307.         $data = '<?xml version="1.0" encoding="UTF-8"?>
  1308.                    <group-membership>
  1309.                      <membership-state>
  1310.                          <code>member</code>
  1311.                      </membership-state>
  1312.                    </group-membership>';
  1313.        
  1314.         // construct and send the request
  1315.         $query    = self::_URL_API . '/v1/people/~/group-memberships/' . trim($gid);
  1316.         $response = $this->fetch('PUT', $query, $data);
  1317.        
  1318.         /**
  1319.        * Check for successful request (a 200 or 201 response from LinkedIn server)
  1320.        * per the documentation linked in method comments above.
  1321.        */
  1322.         return $this->checkResponse(array(200, 201), $response);
  1323.     }
  1324.    
  1325.     /**
  1326.      * Returns the last request header from the previous call to the
  1327.      * LinkedIn API.
  1328.      *
  1329.      * @returns str
  1330.      *    The header, in string format.
  1331.      */            
  1332.     public function lastRequestHeader() {
  1333.        return $this->last_request_headers;
  1334.     }
  1335.    
  1336.     /**
  1337.      * Returns the last request url from the previous call to the
  1338.      * LinkedIn API.
  1339.      *
  1340.      * @returns str
  1341.      *    The url, in string format.
  1342.      */            
  1343.     public function lastRequestUrl() {
  1344.        return $this->last_request_url;
  1345.     }
  1346.    
  1347.     /**
  1348.      * Leave the specified group, per:.
  1349.      *
  1350.      *   http://developer.linkedin.com/documents/groups-api
  1351.      *
  1352.      * @param str $gid
  1353.      *      The group id.
  1354.      *
  1355.      * @return arr
  1356.      *      Array containing retrieval success, LinkedIn response.
  1357.      */
  1358.     public function leaveGroup($gid){
  1359.         if(!is_string($gid)) {
  1360.             throw new LinkedInException('LinkedIn->leaveGroup(): bad data passed, $gid must be of type string');
  1361.         }
  1362.        
  1363.         // construct and send the request
  1364.         $query    = self::_URL_API . '/v1/people/~/group-memberships/'  .trim($gid);
  1365.         $response = $this->fetch('DELETE', $query);
  1366.        
  1367.         /**
  1368.        * Check for successful request (a 204 response from LinkedIn server)
  1369.        * per the documentation linked in method comments above.
  1370.        */
  1371.         return $this->checkResponse(204, $response);
  1372.     }
  1373.    
  1374.     /**
  1375.      * Like another user's network update, per:
  1376.      *
  1377.      *   http://developer.linkedin.com/docs/DOC-1043
  1378.      *
  1379.      * @param str $uid
  1380.      *    The LinkedIn update ID.
  1381.      *                      
  1382.      * @return arr
  1383.      *    Array containing retrieval success, LinkedIn response.                  
  1384.      */
  1385.     public function like($uid) {
  1386.       // check passed data
  1387.       if(!is_string($uid)) {
  1388.         // bad data passed
  1389.           throw new LinkedInException('LinkedIn->like(): bad data passed, $uid must be of type string.');
  1390.       }
  1391.    
  1392.     // construct the XML
  1393.         $data = '<?xml version="1.0" encoding="UTF-8"?>
  1394.                  <is-liked>true</is-liked>';
  1395.        
  1396.         // construct and send the request
  1397.     $query    = self::_URL_API . '/v1/people/~/network/updates/key=' . $uid . '/is-liked';
  1398.     $response = $this->fetch('PUT', $query, $data);
  1399.    
  1400.     /**
  1401.        * Check for successful request (a 201 response from LinkedIn server)
  1402.        * per the documentation linked in method comments above.
  1403.        */
  1404.     return $this->checkResponse(201, $response);
  1405.     }
  1406.    
  1407.     /**
  1408.      * Likes/unlikes the specified post, per:
  1409.      *
  1410.      *   http://developer.linkedin.com/documents/groups-api
  1411.      *
  1412.      * @param str $pid
  1413.      *      The post id.
  1414.      * @param bool $like
  1415.      *      Determines whether to like or unlike. TRUE = like, FALSE = unlike.
  1416.      *
  1417.      * @return arr
  1418.      *      Array containing retrieval success, LinkedIn response.
  1419.      */
  1420.     public function likePost($pid, $like) {
  1421.         if(!is_string($pid)) {
  1422.             throw new LinkedInException ('LinkedIn->likePost(): bad data passed, $pid must be of type string');
  1423.         }
  1424.         if(!($like === TRUE || $like === FALSE)) {
  1425.             throw new LinkedInException('LinkedIn->likePost(): bad data passed, $like must be of type boolean');
  1426.         }
  1427.        
  1428.         // construct the XML
  1429.         $data = '<?xml version="1.0" encoding="UTF-8"?>
  1430.                  <is-liked>'.(($like) ? 'true': 'false').'</is-liked>';
  1431.        
  1432.         // construct and send the request
  1433.         $query    = self::_URL_API . '/v1/posts/' . trim($pid) . '/relation-to-viewer/is-liked';
  1434.         $response = $this->fetch('PUT', $query, $data);
  1435.        
  1436.         /**
  1437.        * Check for successful request (a 204 response from LinkedIn server)
  1438.        * per the documentation linked in method comments above.
  1439.        */
  1440.         return $this->checkResponse(204, $response);
  1441.     }
  1442.    
  1443.     /**
  1444.      * Retrieve network update likes.
  1445.      *    
  1446.      * Return all likes associated with a given network update:
  1447.      *
  1448.      * http://developer.linkedin.com/docs/DOC-1043
  1449.      *
  1450.      * @param str $uid
  1451.      *    The LinkedIn update ID.
  1452.      *                      
  1453.      * @return arr
  1454.      *    Array containing retrieval success, LinkedIn response.                  
  1455.      */
  1456.     public function likes($uid) {
  1457.       // check passed data
  1458.       if(!is_string($uid)) {
  1459.         // bad data passed
  1460.           throw new LinkedInException('LinkedIn->likes(): bad data passed, $uid must be of type string.');
  1461.       }
  1462.        
  1463.         // construct and send the request
  1464.     $query    = self::_URL_API . '/v1/people/~/network/updates/key=' . $uid . '/likes';
  1465.     $response = $this->fetch('GET', $query);
  1466.    
  1467.     /**
  1468.        * Check for successful request (a 200 response from LinkedIn server)
  1469.        * per the documentation linked in method comments above.
  1470.        */
  1471.     return $this->checkResponse(200, $response);
  1472.     }
  1473.    
  1474.     /**
  1475.      * Connection messaging method.
  1476.      *  
  1477.      * Send a message to your network connection(s), optionally copying yourself.  
  1478.      * Full details from LinkedIn on this functionality can be found here:
  1479.      *
  1480.      *   http://developer.linkedin.com/docs/DOC-1044
  1481.      *
  1482.      * @param arr $recipients
  1483.      *    The connection(s) to send the message to.      
  1484.      * @param str $subject
  1485.      *    The subject of the message to send.
  1486.      * @param str $body
  1487.      *    The body of the message to send.
  1488.      * @param bool $copy_self
  1489.      *    [OPTIONAL] Also update the teathered Twitter account.
  1490.      *       
  1491.      * @return arr
  1492.      *    Array containing retrieval success, LinkedIn response.         
  1493.      */
  1494.     public function message($recipients, $subject, $body, $copy_self = FALSE) {
  1495.     /**
  1496.      * Clean up the passed data per these rules:
  1497.      *
  1498.      * 1) Message must be sent to at least one recipient
  1499.      * 2) No HTML permitted
  1500.      */
  1501.     if(!empty($subject) && is_string($subject)) {
  1502.       $subject = trim(strip_tags(stripslashes($subject)));
  1503.     } else {
  1504.       throw new LinkedInException('LinkedIn->message(): bad data passed, $subject must be of type string.');
  1505.     }
  1506.     if(!empty($body) && is_string($body)) {
  1507.       $body = trim(strip_tags(stripslashes($body)));
  1508.     } else {
  1509.       throw new LinkedInException('LinkedIn->message(): bad data passed, $body must be of type string.');
  1510.     }
  1511.     if(!is_array($recipients) || count($recipients) < 1) {
  1512.       // no recipients, and/or bad data
  1513.       throw new LinkedInException('LinkedIn->message(): at least one message recipient required.');
  1514.     }
  1515.    
  1516.     // construct the xml data
  1517.         $data   = '<?xml version="1.0" encoding="UTF-8"?>
  1518.                    <mailbox-item>
  1519.                      <recipients>';
  1520.     $data  .=     ($copy_self) ? '<recipient><person path="/people/~"/></recipient>' : '';
  1521.                   for($i = 0; $i < count($recipients); $i++) {
  1522.                     if(is_string($recipients[$i])) {
  1523.                       $data .= '<recipient><person path="/people/' . trim($recipients[$i]) . '"/></recipient>';
  1524.                     } else {
  1525.                       throw new LinkedInException ('LinkedIn->message(): bad data passed, $recipients must be an array of type string.');
  1526.                     }
  1527.                   }
  1528.     $data  .= '  </recipients>
  1529.                  <subject>' . htmlspecialchars($subject) . '</subject>
  1530.                  <body>' . htmlspecialchars($body) . '</body>
  1531.                </mailbox-item>';
  1532.    
  1533.     // send request
  1534.     $query    = self::_URL_API . '/v1/people/~/mailbox';
  1535.     $response = $this->fetch('POST', $query, $data);
  1536.        
  1537.         /**
  1538.        * Check for successful request (a 201 response from LinkedIn server)
  1539.        * per the documentation linked in method comments above.
  1540.        */
  1541.     return $this->checkResponse(201, $response);
  1542.     }
  1543.    
  1544.     /**
  1545.      * Job posting method.
  1546.      *  
  1547.      * Post a job to LinkedIn, assuming that you have access to this feature.
  1548.      * Full details from LinkedIn on this functionality can be found here:
  1549.      *
  1550.      *   http://developer.linkedin.com/community/jobs?view=documents
  1551.      *
  1552.      * @param str $xml
  1553.      *    The XML defining a job to post.        
  1554.      *       
  1555.      * @return arr
  1556.      *    Array containing retrieval success, LinkedIn response.         
  1557.      */
  1558.     public function postJob($xml) {
  1559.     // check passed data
  1560.     if(is_string($xml)) {
  1561.       $xml = trim(stripslashes($xml));
  1562.     } else {
  1563.       throw new LinkedInException('LinkedIn->postJob(): bad data passed, $xml must be of type string.');
  1564.     }
  1565.    
  1566.     // construct and send the request
  1567.     $query    = self::_URL_API . '/v1/jobs';
  1568.     $response = $this->fetch('POST', $query, $xml);
  1569.        
  1570.         /**
  1571.        * Check for successful request (a 201 response from LinkedIn server)
  1572.        * per the documentation linked in method comments above.
  1573.        */
  1574.     return $this->checkResponse(201, $response);
  1575.     }
  1576.    
  1577.     /**
  1578.      * General profile retrieval function.
  1579.      *
  1580.      * Takes a string of parameters as input and requests profile data from the
  1581.      * Linkedin Profile API. See the official documentation for $options
  1582.      * 'field selector' formatting:
  1583.      *
  1584.      *   http://developer.linkedin.com/docs/DOC-1014
  1585.      *   http://developer.linkedin.com/docs/DOC-1002    
  1586.      *
  1587.      * @param str $options
  1588.      *    [OPTIONAL] Data retrieval options.
  1589.      *               
  1590.      * @return arr
  1591.      *    Array containing retrieval success, LinkedIn response.
  1592.      */
  1593.     public function profile($options = '~') {
  1594.       // check passed data
  1595.       if(!is_string($options)) {
  1596.         // bad data passed
  1597.           throw new LinkedInException('LinkedIn->profile(): bad data passed, $options must be of type string.');
  1598.       }
  1599.      
  1600.       // construct and send the request
  1601.       $query    = self::_URL_API . '/v1/people/' . trim($options);
  1602.       $response = $this->fetch('GET', $query);
  1603.      
  1604.       /**
  1605.        * Check for successful request (a 200 response from LinkedIn server)
  1606.        * per the documentation linked in method comments above.
  1607.        */
  1608.       return $this->checkResponse(200, $response);
  1609.     }
  1610.    
  1611.     /**
  1612.      * Manual API call method, allowing for support for un-implemented API
  1613.      * functionality to be supported.
  1614.      *
  1615.      * @param str $method
  1616.      *    The data communication method.     
  1617.      * @param str $url
  1618.      *    The Linkedin API endpoint to connect with - should NOT include the
  1619.      *    leading https://api.linkedin.com/v1.
  1620.      * @param str $body
  1621.      *    [OPTIONAL] The URL-encoded body data to send to LinkedIn with the request.
  1622.      *
  1623.      * @return arr
  1624.      *      Array containing retrieval information, LinkedIn response. Note that you
  1625.      *      must manually check the return code and compare this to the expected
  1626.      *      API response to determine  if the raw call was successful.
  1627.      */
  1628.     public function raw($method, $url, $body = NULL) {
  1629.       if(!is_string($method)) {
  1630.         // bad data passed
  1631.           throw new LinkedInException('LinkedIn->raw(): bad data passed, $method must be of string value.');
  1632.       }
  1633.       if(!is_string($url)) {
  1634.         // bad data passed
  1635.           throw new LinkedInException('LinkedIn->raw(): bad data passed, $url must be of string value.');
  1636.       }
  1637.       if(!is_null($body) && !is_string($url)) {
  1638.         // bad data passed
  1639.           throw new LinkedInException('LinkedIn->raw(): bad data passed, $body must be of string value.');
  1640.       }
  1641.    
  1642.     // construct and send the request
  1643.       $query = self::_URL_API . '/v1' . trim($url);
  1644.       return $this->fetch($method, $query, $body);
  1645.     }
  1646.    
  1647.     /**
  1648.      * This removes the specified group from the group suggestions, per:
  1649.      *
  1650.      *   http://developer.linkedin.com/documents/groups-api
  1651.      *
  1652.      * @param str $gid
  1653.      *      The group id.
  1654.      *
  1655.      * @return arr
  1656.      *      Array containing retrieval success, LinkedIn response.
  1657.      */
  1658.     public function removeSuggestedGroup($gid) {
  1659.         if(!is_string($gid)) {
  1660.             throw new LinkedInException('LinkedIn->removeSuggestedGroup(): bad data passed, $gid must be of type string');
  1661.         }
  1662.        
  1663.         // construct and send the request
  1664.         $query    = self::_URL_API . '/v1/people/~/suggestions/groups/'  .trim($gid);
  1665.         $response = $this->fetch('DELETE', $query);
  1666.        
  1667.         /**
  1668.        * Check for successful request (a 204 response from LinkedIn server)
  1669.        * per the documentation linked in method comments above.
  1670.        */
  1671.         return $this->checkResponse(204, $response);
  1672.     }
  1673.    
  1674.     /**
  1675.      * Renew a job.
  1676.      *
  1677.      * Calling this method causes the passed job to be renewed, per:
  1678.      *
  1679.      *   http://developer.linkedin.com/docs/DOC-1154  
  1680.      *
  1681.      * @param str $jid
  1682.      *    Job ID you want to renew.
  1683.      * @param str $cid
  1684.      *    Contract ID that covers the passed Job ID.     
  1685.      *             
  1686.      * @return arr
  1687.      *    Array containing retrieval success, LinkedIn response.
  1688.      */
  1689.     public function renewJob($jid, $cid) {
  1690.       // check passed data
  1691.       if(!is_string($jid)) {
  1692.         // bad data passed
  1693.           throw new LinkedInException('LinkedIn->renewJob(): bad data passed, $jid must be of string value.');
  1694.       }
  1695.       if(!is_string($cid)) {
  1696.         // bad data passed
  1697.           throw new LinkedInException('LinkedIn->renewJob(): bad data passed, $cid must be of string value.');
  1698.       }
  1699.      
  1700.       // construct the xml data
  1701.         $data   = '<?xml version="1.0" encoding="UTF-8"?>
  1702.                    <job>
  1703.                      <contract-id>' . trim($cid) . '</contract-id>
  1704.                  <renewal/>
  1705.                </job>';
  1706.                
  1707.       // construct and send the request
  1708.       $query    = self::_URL_API . '/v1/jobs/partner-job-id=' . trim($jid);
  1709.       $response = $this->fetch('PUT', $query, $data);
  1710.      
  1711.       /**
  1712.        * Check for successful request (a 200 response from LinkedIn server)
  1713.        * per the documentation linked in method comments above.
  1714.        */
  1715.       return $this->checkResponse(200, $response);
  1716.     }
  1717.    
  1718.   /**
  1719.      * Access token retrieval.
  1720.      *
  1721.      * Request the user's access token from the Linkedin API.
  1722.      *
  1723.      * @param str $token
  1724.      *    The token returned from the user authorization stage.
  1725.      * @param str $secret
  1726.      *    The secret returned from the request token stage.
  1727.      * @param str $verifier
  1728.      *    The verification value from LinkedIn.
  1729.      *       
  1730.      * @return arr
  1731.      *    The Linkedin OAuth/http response, in array format.         
  1732.      */
  1733.     public function retrieveTokenAccess($token, $secret, $verifier) {
  1734.       // check passed data
  1735.     if(!is_string($token) || !is_string($secret) || !is_string($verifier)) {
  1736.       // nothing passed, raise an exception
  1737.           throw new LinkedInException('LinkedIn->retrieveTokenAccess(): bad data passed, string type is required for $token, $secret and $verifier.');
  1738.     }
  1739.    
  1740.     // start retrieval process
  1741.       $this->setToken(array('oauth_token' => $token, 'oauth_token_secret' => $secret));
  1742.     $parameters = array(
  1743.       'oauth_verifier' => $verifier
  1744.     );
  1745.     $response = $this->fetch(self::_METHOD_TOKENS, self::_URL_ACCESS, NULL, $parameters);
  1746.     parse_str($response['linkedin'], $response['linkedin']);
  1747.    
  1748.     /**
  1749.        * Check for successful request (a 200 response from LinkedIn server)
  1750.        * per the documentation linked in method comments above.
  1751.        */
  1752.     if($response['info']['http_code'] == 200) {
  1753.       // tokens retrieved
  1754.       $this->setToken($response['linkedin']);
  1755.      
  1756.       // set the response
  1757.       $return_data            = $response;
  1758.       $return_data['success'] = TRUE;
  1759.     } else {
  1760.       // error getting the request tokens
  1761.        $this->setToken(NULL);
  1762.        
  1763.       // set the response
  1764.       $return_data            = $response;
  1765.       $return_data['error']   = 'HTTP response from LinkedIn end-point was not code 200';
  1766.       $return_data['success'] = FALSE;
  1767.     }
  1768.     return $return_data;
  1769.     }
  1770.    
  1771.     /**
  1772.      * Request token retrieval.
  1773.      *
  1774.      * Get the request token from the Linkedin API.
  1775.      *
  1776.      * @return arr
  1777.      *    The Linkedin OAuth/http response, in array format.         
  1778.      */
  1779.     public function retrieveTokenRequest() {
  1780.     $parameters = array(
  1781.       'oauth_callback' => $this->getCallbackUrl()
  1782.     );
  1783.     $response = $this->fetch(self::_METHOD_TOKENS, self::_URL_REQUEST, NULL, $parameters);
  1784.     parse_str($response['linkedin'], $response['linkedin']);
  1785.    
  1786.     /**
  1787.        * Check for successful request (a 200 response from LinkedIn server)
  1788.        * per the documentation linked in method comments above.
  1789.        */
  1790.     if(($response['info']['http_code'] == 200) && (array_key_exists('oauth_callback_confirmed', $response['linkedin'])) && ($response['linkedin']['oauth_callback_confirmed'] == 'true')) {
  1791.       // tokens retrieved
  1792.       $this->setToken($response['linkedin']);
  1793.      
  1794.       // set the response
  1795.       $return_data            = $response;
  1796.       $return_data['success'] = TRUE;        
  1797.     } else {
  1798.       // error getting the request tokens
  1799.       $this->setToken(NULL);
  1800.      
  1801.       // set the response
  1802.       $return_data = $response;
  1803.       if((array_key_exists('oauth_callback_confirmed', $response['linkedin'])) && ($response['linkedin']['oauth_callback_confirmed'] == 'true')) {
  1804.         $return_data['error'] = 'HTTP response from LinkedIn end-point was not code 200';
  1805.       } else {
  1806.         $return_data['error'] = 'OAuth callback URL was not confirmed by the LinkedIn end-point';
  1807.       }
  1808.       $return_data['success'] = FALSE;
  1809.     }
  1810.     return $return_data;
  1811.     }
  1812.    
  1813.     /**
  1814.      * User authorization revocation.
  1815.      *
  1816.      * Revoke the current user's access token, clear the access token's from
  1817.      * current LinkedIn object. The current documentation for this feature is
  1818.      * found in a blog entry from April 29th, 2010:
  1819.      *
  1820.      *   http://developer.linkedin.com/community/apis/blog/2010/04/29/oauth--now-for-authentication  
  1821.      *
  1822.      * @return arr
  1823.      *    Array containing retrieval success, LinkedIn response.    
  1824.      */
  1825.     public function revoke() {
  1826.       // construct and send the request
  1827.       $response = $this->fetch('GET', self::_URL_REVOKE);
  1828.  
  1829.       /**
  1830.        * Check for successful request (a 200 response from LinkedIn server)
  1831.        * per the documentation linked in method comments above.
  1832.        */                    
  1833.     return $this->checkResponse(200, $response);
  1834.     }
  1835.    
  1836.     /**
  1837.      * [DEPRECATED] General people search function.
  1838.      *
  1839.      * Takes a string of parameters as input and requests profile data from the
  1840.      * Linkedin People Search API.  See the official documentation for $options
  1841.      * querystring formatting:
  1842.      *
  1843.      *   http://developer.linkedin.com/docs/DOC-1191
  1844.      *
  1845.      * @param str $options
  1846.      *    [OPTIONAL] Data retrieval options.
  1847.      *               
  1848.      * @return arr
  1849.      *    Array containing retrieval success, LinkedIn response.
  1850.      */
  1851.     public function search($options = NULL) {
  1852.         return searchPeople($options);
  1853.     }
  1854.    
  1855.     /**
  1856.      * Company search.
  1857.      *
  1858.      * Uses the Company Search API to find companies using keywords, industry,
  1859.      * location, or some other criteria. It returns a collection of matching
  1860.      * companies.
  1861.      *
  1862.      *   http://developer.linkedin.com/docs/DOC-1325  
  1863.      *
  1864.      * @param str $options
  1865.      *    [OPTIONAL] Search options.   
  1866.      * @return arr
  1867.      *    Array containing retrieval success, LinkedIn response.
  1868.      */
  1869.     public function searchCompanies($options = '') {
  1870.       // check passed data
  1871.       if(!is_string($options)) {
  1872.         // bad data passed
  1873.           throw new LinkedInException('LinkedIn->searchCompanies(): bad data passed, $options must be of type string.');
  1874.       }
  1875.      
  1876.       // construct and send the request
  1877.       $query    = self::_URL_API . '/v1/company-search' . trim($options);
  1878.       $response = $this->fetch('GET', $query);
  1879.      
  1880.       /**
  1881.        * Check for successful request (a 200 response from LinkedIn server)
  1882.        * per the documentation linked in method comments above.
  1883.        */
  1884.       return $this->checkResponse(200, $response);
  1885.     }
  1886.    
  1887.     /**
  1888.      * Jobs search.
  1889.      *
  1890.      * Use the Job Search API to find jobs using keywords, company, location,
  1891.      * or some other criteria. It returns a collection of matching jobs. Each
  1892.      * entry can contain much of the information available on the job listing.
  1893.      *
  1894.      *   http://developer.linkedin.com/docs/DOC-1321  
  1895.      *
  1896.      * @param str $options
  1897.      *    [OPTIONAL] Data retrieval options.
  1898.      *             
  1899.      * @return arr
  1900.      *    Array containing retrieval success, LinkedIn response.
  1901.      */
  1902.     public function searchJobs($options = '') {
  1903.       // check passed data
  1904.       if(!is_string($options)) {
  1905.         // bad data passed
  1906.           throw new LinkedInException('LinkedIn->jobsSearch(): bad data passed, $options must be of type string.');
  1907.       }
  1908.      
  1909.       // construct and send the request
  1910.       $query    = self::_URL_API . '/v1/job-search' . trim($options);
  1911.       $response = $this->fetch('GET', $query);
  1912.      
  1913.       /**
  1914.        * Check for successful request (a 200 response from LinkedIn server)
  1915.        * per the documentation linked in method comments above.
  1916.        */
  1917.       return $this->checkResponse(200, $response);
  1918.     }
  1919.    
  1920.     /**
  1921.      * General people search function.
  1922.      *
  1923.      * Takes a string of parameters as input and requests profile data from the
  1924.      * Linkedin People Search API.  See the official documentation for $options
  1925.      * querystring formatting:
  1926.      *
  1927.      *   http://developer.linkedin.com/docs/DOC-1191
  1928.      *
  1929.      * @param str $options
  1930.      *    [OPTIONAL] Data retrieval options.
  1931.      *               
  1932.      * @return arr
  1933.      *    Array containing retrieval success, LinkedIn response.
  1934.      */
  1935.     public function searchPeople($options = NULL) {
  1936.       // check passed data
  1937.     if(!is_null($options) && !is_string($options)) {
  1938.         // bad data passed
  1939.           throw new LinkedInException('LinkedIn->search(): bad data passed, $options must be of type string.');
  1940.       }
  1941.      
  1942.       // construct and send the request
  1943.     $query    = self::_URL_API . '/v1/people-search' . trim($options);
  1944.         $response = $this->fetch('GET', $query);
  1945.        
  1946.         /**
  1947.        * Check for successful request (a 200 response from LinkedIn server)
  1948.        * per the documentation linked in method comments above.
  1949.        */
  1950.         return $this->checkResponse(200, $response);
  1951.     }
  1952.    
  1953.     /**
  1954.      * Set the application_key property.
  1955.      *
  1956.      * @param str $key
  1957.      *    The application key.          
  1958.      */
  1959.     public function setApplicationKey($key) {
  1960.       $this->application_key = $key;
  1961.     }
  1962.    
  1963.     /**
  1964.      * Set the application_secret property.
  1965.      *
  1966.      * @param str $secret
  1967.      *    The application secret.            
  1968.      */
  1969.     public function setApplicationSecret($secret) {
  1970.       $this->application_secret = $secret;
  1971.     }
  1972.    
  1973.     /**
  1974.      * Set the callback property.
  1975.      *
  1976.      * @param str $url
  1977.      *    The callback url.          
  1978.      */
  1979.     public function setCallbackUrl($url) {
  1980.       $this->callback = $url;
  1981.     }
  1982.    
  1983.     /**
  1984.      * This sets the group settings of the specified group.
  1985.      *
  1986.      *   http://developer.linkedin.com/documents/groups-api
  1987.      *
  1988.      * @param str $gid
  1989.      *      The group id.
  1990.      * @param str $xml
  1991.      *      The group settings to set. The settings are:
  1992.      *        -<show-group-logo-in-profle>
  1993.      *        -<contact-email>
  1994.      *        -<email-digest-frequency>
  1995.      *        -<email-annoucements-from-managers>
  1996.      *        -<allow-messages-from-members>
  1997.      *        -<email-for-every-new-post>
  1998.      *
  1999.      * @return arr
  2000.      *      Array containing retrieval success, LinkedIn response.
  2001.      */
  2002.     public function setGroupSettings($gid, $xml) {
  2003.         if(!is_string ($gid)) {
  2004.       throw new LinkedInException('LinkedIn->setGroupSettings(): bad data passed, $token_access should be in array format.');
  2005.         }
  2006.         if(!is_string ($xml)) {
  2007.       throw new LinkedInException('LinkedIn->setGroupSettings(): bad data passed, $token_access should be in array format.');
  2008.         }
  2009.        
  2010.         // construct and send the request
  2011.         $query    = self::_URL_API . '/v1/people/~/group-memberships/' . trim($gid);
  2012.         $response = $this->fetch('PUT', $query, $xml);
  2013.        
  2014.       /**
  2015.        * Check for successful request (a 200 response from LinkedIn server)
  2016.        * per the documentation linked in method comments above.
  2017.        */
  2018.         return $this->checkResponse(200, $response);
  2019.     }
  2020.    
  2021.     /**
  2022.      * Set the response_format property.
  2023.      *
  2024.      * @param str $format
  2025.      *    [OPTIONAL] The response format to specify to LinkedIn.        
  2026.      */
  2027.     public function setResponseFormat($format = self::_DEFAULT_RESPONSE_FORMAT) {
  2028.       $this->response_format = $format;
  2029.     }
  2030.    
  2031.     /**
  2032.      * Set the token property.
  2033.      *
  2034.      * @return arr $token
  2035.      *    The LinkedIn OAuth token.
  2036.      */
  2037.     public function setToken($token) {
  2038.     // check passed data
  2039.     if(!is_null($token) && !is_array($token)) {
  2040.       // bad data passed
  2041.       throw new LinkedInException('LinkedIn->setToken(): bad data passed, $token_access should be in array format.');
  2042.     }
  2043.    
  2044.     // set token
  2045.     $this->token = $token;
  2046.     }
  2047.    
  2048.     /**
  2049.      * [DEPRECATED] Set the token_access property.
  2050.      *
  2051.      * @return arr $token_access
  2052.      *    [OPTIONAL] The LinkedIn OAuth access token.
  2053.      */
  2054.     public function setTokenAccess($token_access) {
  2055.     $this->setToken($token_access);
  2056.     }
  2057.    
  2058.     /**
  2059.      * Post a share.
  2060.      *
  2061.      * Create a new or reshare another user's shared content. Full details from
  2062.      * LinkedIn on this functionality can be found here:
  2063.      *
  2064.      *   http://developer.linkedin.com/docs/DOC-1212
  2065.      *
  2066.      *   $action values: ('new', 'reshare')          
  2067.      *   $content format:
  2068.      *     $action = 'new'; $content => ('comment' => 'xxx', 'title' => 'xxx', 'submitted-url' => 'xxx', 'submitted-image-url' => 'xxx', 'description' => 'xxx')
  2069.      *     $action = 'reshare'; $content => ('comment' => 'xxx', 'id' => 'xxx')  
  2070.      *
  2071.      * @param str $action
  2072.      *    The sharing action to perform.     
  2073.      * @param str $content
  2074.      *    The share content.
  2075.      * @param bool $private
  2076.      *    [OPTIONAL] Should we restrict this shared item to connections only?    
  2077.      * @param bool $twitter
  2078.      *    [OPTIONAL] Also update the teathered Twitter account.
  2079.      *       
  2080.      * @return arr
  2081.      *    Array containing retrieval success, LinkedIn response.         
  2082.      */
  2083.     public function share($action, $content, $private = TRUE, $twitter = FALSE) {
  2084.       // check the status itself
  2085.     if(!empty($action) && !empty($content)) {
  2086.       /**
  2087.        * Status is not empty, wrap a cleaned version of it in xml.  Status
  2088.        * rules:
  2089.        *
  2090.        * 1) Comments are 700 chars max (if this changes, change _SHARE_COMMENT_LENGTH constant)
  2091.        * 2) Content/title 200 chars max (if this changes, change _SHARE_CONTENT_TITLE_LENGTH constant)
  2092.        * 3) Content/description 400 chars max (if this changes, change _SHARE_CONTENT_DESC_LENGTH constant)
  2093.        * 4a) New shares must contain a comment and/or (content/title and content/submitted-url)
  2094.        * 4b) Reshared content must contain an attribution id.
  2095.        * 4c) Reshared content must contain actual content, not just a comment.            
  2096.        * 5) No HTML permitted in comment, content/title, content/description.
  2097.        */
  2098.  
  2099.       // prepare the share data per the rules above
  2100.       $share_flag   = FALSE;
  2101.       $content_xml  = NULL;
  2102.       switch($action) {
  2103.         case 'new':
  2104.           // share can be an article
  2105.           if(array_key_exists('title', $content) && array_key_exists('submitted-url', $content)) {
  2106.             // we have shared content, format it as needed per rules above
  2107.             $content_title = trim(htmlspecialchars(strip_tags(stripslashes($content['title']))));
  2108.             if(strlen($content_title) > self::_SHARE_CONTENT_TITLE_LENGTH) {
  2109.               throw new LinkedInException('LinkedIn->share(): title length is too long - max length is ' . self::_SHARE_CONTENT_TITLE_LENGTH . ' characters.');
  2110.             }
  2111.             $content_xml .= '<content>
  2112.                                <title>' . $content_title . '</title>
  2113.                                <submitted-url>' . trim(htmlspecialchars($content['submitted-url'])) . '</submitted-url>';
  2114.             if(array_key_exists('submitted-image-url', $content)) {
  2115.               $content_xml .= '<submitted-image-url>' . trim(htmlspecialchars($content['submitted-image-url'])) . '</submitted-image-url>';
  2116.             }
  2117.             if(array_key_exists('description', $content)) {
  2118.               $content_desc = trim(htmlspecialchars(strip_tags(stripslashes($content['description']))));
  2119.               if(strlen($content_desc) > self::_SHARE_CONTENT_DESC_LENGTH) {
  2120.                 throw new LinkedInException('LinkedIn->share(): description length is too long - max length is ' . self::_SHARE_CONTENT_DESC_LENGTH . ' characters.');
  2121.               }
  2122.               $content_xml .= '<description>' . $content_desc . '</description>';
  2123.             }
  2124.             $content_xml .= '</content>';
  2125.            
  2126.             $share_flag = TRUE;
  2127.           }
  2128.          
  2129.           // share can be just a comment
  2130.           if(array_key_exists('comment', $content)) {
  2131.             // comment located
  2132.             $comment = htmlspecialchars(trim(strip_tags(stripslashes($content['comment']))));
  2133.             if(strlen($comment) > self::_SHARE_COMMENT_LENGTH) {
  2134.               throw new LinkedInException('LinkedIn->share(): comment length is too long - max length is ' . self::_SHARE_COMMENT_LENGTH . ' characters.');
  2135.             }
  2136.             $content_xml .= '<comment>' . $comment . '</comment>';
  2137.            
  2138.             $share_flag = TRUE;
  2139.           }
  2140.           break;
  2141.         case 'reshare':
  2142.           if(array_key_exists('id', $content)) {
  2143.             // put together the re-share attribution XML
  2144.             $content_xml .= '<attribution>
  2145.                                <share>
  2146.                                  <id>' . trim($content['id']) . '</id>
  2147.                                </share>
  2148.                              </attribution>';
  2149.            
  2150.             // optional additional comment
  2151.             if(array_key_exists('comment', $content)) {
  2152.                 // comment located
  2153.                 $comment = htmlspecialchars(trim(strip_tags(stripslashes($content['comment']))));
  2154.                 if(strlen($comment) > self::_SHARE_COMMENT_LENGTH) {
  2155.                 throw new LinkedInException('LinkedIn->share(): comment length is too long - max length is ' . self::_SHARE_COMMENT_LENGTH . ' characters.');
  2156.               }
  2157.               $content_xml .= '<comment>' . $comment . '</comment>';
  2158.               }
  2159.              
  2160.               $share_flag = TRUE;
  2161.           }
  2162.           break;
  2163.         default:
  2164.           // bad action passed
  2165.           throw new LinkedInException('LinkedIn->share(): share action is an invalid value, must be one of: share, reshare.');
  2166.           break;
  2167.       }
  2168.      
  2169.       // should we proceed?
  2170.       if($share_flag) {
  2171.         // put all of the xml together
  2172.         $visibility = ($private) ? 'connections-only' : 'anyone';
  2173.         $data       = '<?xml version="1.0" encoding="UTF-8"?>
  2174.                        <share>
  2175.                          ' . $content_xml . '
  2176.                          <visibility>
  2177.                            <code>' . $visibility . '</code>
  2178.                          </visibility>
  2179.                        </share>';
  2180.        
  2181.         // create the proper url
  2182.         $share_url = self::_URL_API . '/v1/people/~/shares';
  2183.           if($twitter) {
  2184.               // update twitter as well
  2185.           $share_url .= '?twitter-post=true';
  2186.             }
  2187.        
  2188.         // send request
  2189.         $response = $this->fetch('POST', $share_url, $data);
  2190.         } else {
  2191.           // data contraints/rules not met, raise an exception
  2192.             throw new LinkedInException('LinkedIn->share(): sharing data constraints not met; check that you have supplied valid content and combinations of content to share.');
  2193.         }
  2194.     } else {
  2195.       // data missing, raise an exception
  2196.           throw new LinkedInException('LinkedIn->share(): sharing action or shared content is missing.');
  2197.     }
  2198.    
  2199.     /**
  2200.        * Check for successful request (a 201 response from LinkedIn server)
  2201.        * per the documentation linked in method comments above.
  2202.        */
  2203.     return $this->checkResponse(201, $response);
  2204.     }
  2205.    
  2206.     /**
  2207.      * Network statistics.
  2208.      *
  2209.      * General network statistics retrieval function, returns the number of connections,
  2210.      * second-connections an authenticated user has. More information here:
  2211.      *
  2212.      *   http://developer.linkedin.com/docs/DOC-1006
  2213.      *
  2214.      * @return arr
  2215.      *    Array containing retrieval success, LinkedIn response.
  2216.      */
  2217.     public function statistics() {
  2218.       // construct and send the request
  2219.     $query    = self::_URL_API . '/v1/people/~/network/network-stats';
  2220.         $response = $this->fetch('GET', $query);
  2221.        
  2222.         /**
  2223.        * Check for successful request (a 200 response from LinkedIn server)
  2224.        * per the documentation linked in method comments above.
  2225.        */
  2226.         return $this->checkResponse(200, $response);
  2227.     }
  2228.    
  2229.     /**
  2230.      * Companies you may want to follow.
  2231.      *
  2232.      * Returns a list of companies the current user may want to follow, per:
  2233.      *
  2234.      *   http://developer.linkedin.com/docs/DOC-1324  
  2235.      *
  2236.      * @return arr
  2237.      *    Array containing retrieval success, LinkedIn response.
  2238.      */
  2239.     public function suggestedCompanies() {
  2240.       // construct and send the request
  2241.     $query    = self::_URL_API . '/v1/people/~/suggestions/to-follow/companies';
  2242.       $response = $this->fetch('GET', $query);
  2243.      
  2244.       /**
  2245.        * Check for successful request (a 200 response from LinkedIn server)
  2246.        * per the documentation linked in method comments above.
  2247.        */
  2248.       return $this->checkResponse(200, $response);
  2249.     }
  2250.    
  2251.     /**
  2252.      * Retrieves suggested groups for the user, per:
  2253.      *
  2254.      *   http://developer.linkedin.com/documents/groups-api
  2255.      *
  2256.      * @return arr
  2257.      *      Array containing retrieval success, LinkedIn response.
  2258.      */
  2259.     public function suggestedGroups() {
  2260.         // construct and send the request
  2261.         $query    = self::_URL_API . '/v1/people/~/suggestions/groups:(id,name,is-open-to-non-members)';
  2262.         $response = $this->fetch('GET', $query);
  2263.        
  2264.         /**
  2265.        * Check for successful request (a 200 response from LinkedIn server)
  2266.        * per the documentation linked in method comments above.
  2267.        */
  2268.         return $this->checkResponse (200, $response);
  2269.     }
  2270.  
  2271.     /**
  2272.      * Jobs you may be interested in.
  2273.      *
  2274.      * Returns a list of jobs the current user may be interested in, per:
  2275.      *
  2276.      *   http://developer.linkedin.com/docs/DOC-1323  
  2277.      *
  2278.      * @param str $options
  2279.      *    [OPTIONAL] Data retrieval options.   
  2280.      *               
  2281.      * @return arr
  2282.      *    Array containing retrieval success, LinkedIn response.
  2283.      */
  2284.     public function suggestedJobs($options = ':(jobs)') {
  2285.       // check passed data
  2286.       if(!is_string($options)) {
  2287.         // bad data passed
  2288.           throw new LinkedInException('LinkedIn->suggestedJobs(): bad data passed, $options must be of type string.');
  2289.       }
  2290.    
  2291.       // construct and send the request
  2292.       $query    = self::_URL_API . '/v1/people/~/suggestions/job-suggestions' . trim($options);
  2293.       $response = $this->fetch('GET', $query);
  2294.      
  2295.       /**
  2296.        * Check for successful request (a 200 response from LinkedIn server)
  2297.        * per the documentation linked in method comments above.
  2298.        */
  2299.       return $this->checkResponse(200, $response);
  2300.     }
  2301.    
  2302.     /**
  2303.      * Unbookmark a job.
  2304.      *
  2305.      * Calling this method causes the current user to remove a bookmark for the
  2306.      * specified job:
  2307.      *
  2308.      *   http://developer.linkedin.com/docs/DOC-1323  
  2309.      *
  2310.      * @param str $jid
  2311.      *    Job ID you want to unbookmark.
  2312.      *             
  2313.      * @return arr
  2314.      *    Array containing retrieval success, LinkedIn response.
  2315.      */
  2316.     public function unbookmarkJob($jid) {
  2317.       // check passed data
  2318.       if(!is_string($jid)) {
  2319.         // bad data passed
  2320.           throw new LinkedInException('LinkedIn->unbookmarkJob(): bad data passed, $jid must be of type string.');
  2321.       }
  2322.      
  2323.       // construct and send the request
  2324.       $query    = self::_URL_API . '/v1/people/~/job-bookmarks/' . trim($jid);
  2325.       $response = $this->fetch('DELETE', $query);
  2326.      
  2327.       /**
  2328.        * Check for successful request (a 204 response from LinkedIn server)
  2329.        * per the documentation linked in method comments above.
  2330.        */
  2331.       return $this->checkResponse(204, $response);
  2332.     }
  2333.    
  2334.     /**
  2335.      * Unfollow a company.
  2336.      *
  2337.      * Calling this method causes the current user to stop following the specified
  2338.      * company, per:
  2339.      *
  2340.      *   http://developer.linkedin.com/docs/DOC-1324  
  2341.      *
  2342.      * @param str $cid
  2343.      *    Company ID you want to unfollow. 
  2344.      *          
  2345.      * @return arr
  2346.      *    Array containing retrieval success, LinkedIn response.
  2347.      */
  2348.     public function unfollowCompany($cid) {
  2349.       // check passed data
  2350.       if(!is_string($cid)) {
  2351.         // bad data passed
  2352.           throw new LinkedInException('LinkedIn->unfollowCompany(): bad data passed, $cid must be of string value.');
  2353.       }
  2354.      
  2355.       // construct and send the request
  2356.       $query    = self::_URL_API . '/v1/people/~/following/companies/id=' . trim($cid);
  2357.       $response = $this->fetch('DELETE', $query);
  2358.      
  2359.       /**
  2360.        * Check for successful request (a 204 response from LinkedIn server)
  2361.        * per the documentation linked in method comments above.
  2362.        */
  2363.       return $this->checkResponse(204, $response);
  2364.     }
  2365.    
  2366.     /**
  2367.      * Unlike a network update.
  2368.      *    
  2369.      * Unlike another user's network update:
  2370.      *
  2371.      *   http://developer.linkedin.com/docs/DOC-1043
  2372.      *
  2373.      * @param str $uid
  2374.      *    The LinkedIn update ID.
  2375.      *                      
  2376.      * @return arr
  2377.      *    Array containing retrieval success, LinkedIn response.                  
  2378.      */
  2379.     public function unlike($uid) {
  2380.       // check passed data
  2381.       if(!is_string($uid)) {
  2382.         // bad data passed
  2383.           throw new LinkedInException('LinkedIn->unlike(): bad data passed, $uid must be of type string.');
  2384.       }
  2385.    
  2386.     // construct the xml data
  2387.         $data = '<?xml version="1.0" encoding="UTF-8"?>
  2388.                  <is-liked>false</is-liked>';
  2389.        
  2390.         // send request
  2391.     $query    = self::_URL_API . '/v1/people/~/network/updates/key=' . $uid . '/is-liked';
  2392.     $response = $this->fetch('PUT', $query, $data);
  2393.    
  2394.     /**
  2395.        * Check for successful request (a 201 response from LinkedIn server)
  2396.        * per the documentation linked in method comments above.
  2397.        */
  2398.     return $this->checkResponse(201, $response);
  2399.     }
  2400.    
  2401.     /**
  2402.      * Post network update.
  2403.      *
  2404.      * Update the user's Linkedin network status. Full details from LinkedIn
  2405.      * on this functionality can be found here:
  2406.      *
  2407.      *   http://developer.linkedin.com/docs/DOC-1009
  2408.      *   http://developer.linkedin.com/docs/DOC-1009#comment-1077
  2409.      *
  2410.      * @param str $update
  2411.      *    The network update.    
  2412.      *
  2413.      * @return arr
  2414.      *    Array containing retrieval success, LinkedIn response.        
  2415.      */
  2416.     public function updateNetwork($update) {
  2417.       // check passed data
  2418.     if(!is_string($update)) {
  2419.       // nothing/non-string passed, raise an exception
  2420.           throw new LinkedInException('LinkedIn->updateNetwork(): bad data passed, $update must be a non-zero length string.');
  2421.     }
  2422.    
  2423.     /**
  2424.      * Network update is not empty, wrap a cleaned version of it in xml.  
  2425.      * Network update rules:
  2426.      *
  2427.      * 1) No HTML permitted except those found in _NETWORK_HTML constant
  2428.      * 2) Update cannot be longer than 140 characters.    
  2429.      */
  2430.     // get the user data
  2431.     $response = self::profile('~:(first-name,last-name,site-standard-profile-request)');
  2432.     if($response['success'] === TRUE) {
  2433.       /**
  2434.        * We are converting response to usable data.  I'd use SimpleXML here, but
  2435.        * to keep the class self-contained, we will use a portable XML parsing
  2436.        * routine, self::xmlToArray.      
  2437.        */
  2438.       $person = self::xmlToArray($response['linkedin']);
  2439.       if($person === FALSE) {
  2440.         // bad xml data
  2441.         throw new LinkedInException('LinkedIn->updateNetwork(): LinkedIn returned bad XML data.');
  2442.       }
  2443.         $fields = $person['person']['children'];
  2444.  
  2445.         // prepare user data
  2446.         $first_name   = trim($fields['first-name']['content']);
  2447.         $last_name    = trim($fields['last-name']['content']);
  2448.         $profile_url  = trim($fields['site-standard-profile-request']['children']['url']['content']);
  2449.  
  2450.       // create the network update
  2451.       $update = trim(htmlspecialchars(strip_tags($update, self::_NETWORK_HTML)));
  2452.       if(strlen($update) > self::_NETWORK_LENGTH) {
  2453.         throw new LinkedInException('LinkedIn->share(): update length is too long - max length is ' . self::_NETWORK_LENGTH . ' characters.');
  2454.       }
  2455.       $user   = htmlspecialchars('<a href="' . $profile_url . '">' . $first_name . ' ' . $last_name . '</a>');
  2456.         $data   = '<activity locale="en_US">
  2457.                            <content-type>linkedin-html</content-type>
  2458.                            <body>' . $user . ' ' . $update . '</body>
  2459.                          </activity>';
  2460.  
  2461.       // send request
  2462.       $query    = self::_URL_API . '/v1/people/~/person-activities';
  2463.       $response = $this->fetch('POST', $query, $data);
  2464.      
  2465.       /**
  2466.        * Check for successful request (a 201 response from LinkedIn server)
  2467.        * per the documentation linked in method comments above.
  2468.        */
  2469.       return $this->checkResponse(201, $response);
  2470.     } else {
  2471.       // profile retrieval failed
  2472.       throw new LinkedInException('LinkedIn->updateNetwork(): profile data could not be retrieved.');
  2473.     }
  2474.     }
  2475.    
  2476.   /**
  2477.      * General network update retrieval function.
  2478.      *
  2479.      * Takes a string of parameters as input and requests update-related data
  2480.      * from the Linkedin Network Updates API. See the official documentation for
  2481.      * $options parameter formatting:
  2482.      *
  2483.      *   http://developer.linkedin.com/docs/DOC-1006
  2484.      *
  2485.      * For getting more comments, likes, etc, see here:
  2486.      *
  2487.      *   http://developer.linkedin.com/docs/DOC-1043            
  2488.      *
  2489.      * @param str $options
  2490.      *    [OPTIONAL] Data retrieval options.
  2491.      * @param str $id
  2492.      *    [OPTIONAL] The LinkedIn ID to restrict the updates for.
  2493.      *                  
  2494.      * @return arr
  2495.      *    Array containing retrieval success, LinkedIn response.
  2496.      */
  2497.     public function updates($options = NULL, $id = NULL) {
  2498.       // check passed data
  2499.     if(!is_null($options) && !is_string($options)) {
  2500.         // bad data passed
  2501.           throw new LinkedInException('LinkedIn->updates(): bad data passed, $options must be of type string.');
  2502.       }
  2503.       if(!is_null($id) && !is_string($id)) {
  2504.         // bad data passed
  2505.           throw new LinkedInException('LinkedIn->updates(): bad data passed, $id must be of type string.');
  2506.       }
  2507.      
  2508.       // construct and send the request
  2509.       if(!is_null($id) && self::isId($id)) {
  2510.         $query = self::_URL_API . '/v1/people/' . $id . '/network/updates' . trim($options);
  2511.       } else {
  2512.       $query = self::_URL_API . '/v1/people/~/network/updates' . trim($options);
  2513.     }
  2514.       $response = $this->fetch('GET', $query);
  2515.      
  2516.       /**
  2517.        * Check for successful request (a 200 response from LinkedIn server)
  2518.        * per the documentation linked in method comments above.
  2519.        */
  2520.       return $this->checkResponse(200, $response);
  2521.     }
  2522.    
  2523.     /**
  2524.      * Converts passed XML data to an array.
  2525.      *
  2526.      * @param str $xml
  2527.      *    The XML to convert to an array.
  2528.      *               
  2529.      * @return arr
  2530.      *    Array containing the XML data.    
  2531.      * @return bool
  2532.      *    FALSE if passed data cannot be parsed to an array.        
  2533.      */
  2534.     public static function xmlToArray($xml) {
  2535.       // check passed data
  2536.     if(!is_string($xml)) {
  2537.         // bad data possed
  2538.       throw new LinkedInException('LinkedIn->xmlToArray(): bad data passed, $xml must be a non-zero length string.');
  2539.       }
  2540.      
  2541.       $parser = xml_parser_create();
  2542.       xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
  2543.     xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
  2544.     if(xml_parse_into_struct($parser, $xml, $tags)) {
  2545.         $elements = array();
  2546.       $stack    = array();
  2547.       foreach($tags as $tag) {
  2548.         $index = count($elements);
  2549.         if($tag['type'] == 'complete' || $tag['type'] == 'open') {
  2550.           $elements[$tag['tag']]               = array();
  2551.           $elements[$tag['tag']]['attributes'] = (array_key_exists('attributes', $tag)) ? $tag['attributes'] : NULL;
  2552.           $elements[$tag['tag']]['content']    = (array_key_exists('value', $tag)) ? $tag['value'] : NULL;
  2553.           if($tag['type'] == 'open') {
  2554.             $elements[$tag['tag']]['children'] = array();
  2555.             $stack[count($stack)] = &$elements;
  2556.             $elements = &$elements[$tag['tag']]['children'];
  2557.           }
  2558.         }
  2559.         if($tag['type'] == 'close') {
  2560.           $elements = &$stack[count($stack) - 1];
  2561.           unset($stack[count($stack) - 1]);
  2562.         }
  2563.       }
  2564.       $return_data = $elements;
  2565.       } else {
  2566.         // not valid xml data
  2567.         $return_data = FALSE;
  2568.       }
  2569.       xml_parser_free($parser);
  2570.     return $return_data;
  2571.   }
  2572. }
  2573.  
  2574. ?>
RAW Paste Data