Search code examples
linkedin-api

LinkedIn API - how to post company update using Oauth2 & PHP


I am trying to modify LinkedIn's sample authorization code to post a company update.

Have the original code example working, meaning I can login to my user profile. So the next step would be posting the update.

Have found some info on the Internet and here at stackoverflow.com, and the result is the function PostUpdate() found in the code below. The rest of the code pretty much comes straight from the Linkedin code sample.

So this code seems to run, I get no errors reported, but I also get no update on the company page. There is one issue I notice, after successfully logging-in, the code prints "Hello $user->firstName $user->lastName." but my name does NOT show up on the screen. The "Hello" does, so perhaps this indicates where a problem might be found.

<?php
//config.php contains the API KEY, SECRET, AND COMPANY ID
    //define('API_KEY',      'your key');
    //define('API_SECRET',   'your secret');
    //define('COMPANY_ID',   'your company id');
require_once('config.php');

// You must pre-register your redirect_uri at https://www.linkedin.com/secure/developer
define('REDIRECT_URI', 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME']);
define('SCOPE',        'r_basicprofile r_emailaddress w_share rw_company_admin');

// You'll probably use a database
session_name('linkedin');
session_start();

// OAuth 2 Control Flow
if (isset($_GET['error'])) {
    // LinkedIn returned an error
    print $_GET['error'] . ': ' . $_GET['error_description'];
    exit;
} elseif (isset($_GET['code'])) {
    // User authorized your application
    if ($_SESSION['state'] == $_GET['state']) {
        // Get token so you can make API calls
        getAccessToken();
    } else {
        // CSRF attack? Or did you mix up your states?
        exit;
    }
} else {
    if ((empty($_SESSION['expires_at'])) || (time() > $_SESSION['expires_at'])) {
        // Token has expired, clear the state
        $_SESSION = array();
    }
    if (empty($_SESSION['access_token'])) {
        // Start authorization process
        getAuthorizationCode();
    }
}

// Congratulations! You have a valid token. Now fetch your profile
$user = fetch('GET', '/v1/people/~:(firstName,lastName)');

print "Hello $user->firstName $user->lastName.";

// temporary message content for test purposes
    $xml_txt = "<?xml version='1.0' encoding='UTF-8'?> 
      <share>
      <visibility>
        <code>anyone</code>
      </visibility>
      <comment>Testing a full company share!!!!!</comment>
      <content>
        <submitted­-url>https://www.example.com/test-2.html</submitted-­url>
        <title>Test Share with Content</title>
        <description>content description</description>
        <submitted-image-­url>https://www.example.com/img/internet.jpg</submitted­-image-­url>
      </content>
    </share>";

    //Post the message    
$result = PostUpdate($xml_txt);

//Done
exit;

function PostUpdate($message) {   
     print $_SESSION['access_token'];

    $url = 'https://api.linkedin.com/v1/companies/'. COMPANY_ID . '/shares';
    // build your message
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $message );
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/xml', 'Authorization: Bearer ' . $this->access_token));
    $response = curl_exec($ch);
    $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    print_r($response);
    echo $http_status;
} 

function getAuthorizationCode() {
    $params = array(
        'response_type' => 'code',
        'client_id' => API_KEY,
        'scope' => SCOPE,
        'state' => uniqid('', true), // unique long string
        'redirect_uri' => REDIRECT_URI,
    );

    // Authentication request
    $url = 'https://www.linkedin.com/uas/oauth2/authorization?' . http_build_query($params);

    // Needed to identify request when it returns to us
    $_SESSION['state'] = $params['state'];

    // Redirect user to authenticate
    header("Location: $url");
    exit;
}

function getAccessToken() {
    $params = array(
        'grant_type' => 'authorization_code',
        'client_id' => API_KEY,
        'client_secret' => API_SECRET,
        'code' => $_GET['code'],
        'redirect_uri' => REDIRECT_URI,
    );

    // Access Token request
    $url = 'https://www.linkedin.com/uas/oauth2/accessToken?' . http_build_query($params);

    // Tell streams to make a POST request
    $context = stream_context_create(
        array('http' =>
            array('method' => 'POST',
            )
        )
    );

    // Retrieve access token information
    $response = file_get_contents($url, false, $context);

    // Native PHP object, please
    $token = json_decode($response);

    // Store access token and expiration time
    $_SESSION['access_token'] = $token->access_token; // guard this!
    $_SESSION['expires_in']   = $token->expires_in; // relative time (in seconds)
    $_SESSION['expires_at']   = time() + $_SESSION['expires_in']; // absolute time

    return true;
}

function fetch($method, $resource, $body = '') {
    print $_SESSION['access_token'];

    $opts = array(
        'http'=>array(
            'method' => $method,
            'header' => "Authorization: Bearer " . $_SESSION['access_token'] . "\r\n" . "x-li-format: json\r\n"
        )
    );

    // Need to use HTTPS
    $url = 'https://api.linkedin.com' . $resource;

    // Append query parameters (if there are any)
    if (count($params)) { $url .= '?' . http_build_query($params); }

    // Tell streams to make a (GET, POST, PUT, or DELETE) request
    // And use OAuth 2 access token as Authorization
    $context = stream_context_create($opts);

    // Hocus Pocus
    $response = file_get_contents($url, false, $context);

    // Native PHP object, please
    return json_decode($response);
}

Solution

  • Finally posted a company update (share) successfully.

    One issue that made the LinkedIn code sample (https://developer-programs.linkedin.com/documents/code-samples) non-functional was that file_get_contents() was not working, and this was because allow_url_fopen was not enabled in PHP.ini. I believe allow_url_fopen is not enabled by default, as it is a security issue. I found a work-around online use cUrl. See the code below.

    //First, in getAccessToken() replace:

     $response = file_get_contents($url, false, $context)
    

    with

    $response = curl_get_contents($url);
    

    And here is the code added to the LinkedIn code sample, after the 'print "Hello $user->firstName $user->lastName.";'

    // temporary message content for test purposes
    $xml_txt = "<?xml version='1.0' encoding='UTF-8'?> 
      <share>
        <visibility>
          <code>anyone</code>
         </visibility>
          <comment>There are a lot of great career opportunities here!</comment>
       </share>";
    
    //Post the message    
    $result = PostUpdate($xml_txt);
    
    //Done
    exit;
    
    function PostUpdate($message) {   
         print 'here in PostUpdate <br />';
         print '$message = ' . $message .' <br />';
        $url = 'https://api.linkedin.com/v1/companies/'. COMPANY_ID . '/shares';
        // build your message
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $message );
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/xml', 'Authorization: Bearer ' . $_SESSION['access_token']));
        $response = curl_exec($ch);
        $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        print_r($response);
        echo '$http_status = '. $http_status;
    } 
    
    
    function curl_get_contents($url)
    {
        $ch = curl_init();
    
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
    
        $data = curl_exec($ch);
        curl_close($ch);
    
        return $data;
    }
    

    Maybe it aint pretty, but after a couple of days struggling with it, I feel surprisingly elated. And thank you LinkedIn for providing a lets-all-reinvent the-wheel code sample with a built-in "issue". If you folks wipe your tail-ends the same half-arsed way you provide code samples, yer walking around with three inches of dried skidmarks in yer undies. Crusty, you know whut I'm sayin.