Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

oauth file from linkedin

By: a guest on Jun 21st, 2012  |  syntax: PHP  |  size: 87.59 KB  |  views: 69  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  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. ?>