Reputation: 21
I try to upload text, image and a link using Linkedins rest API (https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/share-on-linkedin#create-an-image-share). But I do not succeed. Uploading the post returns an error: ERROR :: /content/article/thumbnail :: Invalid Urn format. Invalid prefix. Urn urn:li:digitalmediaAsset:...
Here is my code. Are there ideas or any hints?
// upload image
$uploadUrl = 'https://api.linkedin.com/rest/assets?action=registerUpload';
$requestData = [
'registerUploadRequest' => [
'recipes' => ['urn:li:digitalmediaRecipe:feedshare-image'],
'owner' => 'urn:li:person:'. $this->provider->linkedin_id,
],
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $uploadUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $this->provider->social_access_token,
'Linkedin-Version: '. $this->linkedin_version,
'Content-Type: application/json',
]);
$response = curl_exec($ch);
// get asset id
$responseArray = json_decode($response, true);
$assetId = $responseArray['value']['asset'];
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 200) {
// upload picture to url received in response
$imagePath = rex_path::media($used_machine->pics[0]);
$uploadUrl = $responseArray['value']['uploadMechanism']['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest']['uploadUrl'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $uploadUrl);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($imagePath));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $this->provider->social_access_token,
'Content-Type: '. mime_content_type($imagePath),
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 201) {
$this->log('Image "'. $used_machine->pics[0].'" for used machine "'. trim($used_machine->manufacturer .' '. $used_machine->name) .'" uploded. Asset ID: '. $assetId);
} else {
// failure uploading image
$this->log('Failure uploading image "'. $used_machine->pics[0].'" for used machine "'. trim($used_machine->manufacturer .' '. $used_machine->name) .'". API answer: '. $response);
$return = false;
}
}
// upload post
if($assetId !== '') {
$postUrl = 'https://api.linkedin.com/rest/posts';
$postData = [
'author' => 'urn:li:person:'. $this->provider->linkedin_id,
'commentary' => $used_machine->manufacturer .' '. $used_machine->name .': '. \Sprog\Wildcard::get('d2u_machinery_export_linkedin_details', $this->provider->clang_id),
'contentLandingPage' => $used_machine->getUrl(true),
'visibility' => 'PUBLIC',
'distribution' => [
'feedDistribution' => 'MAIN_FEED',
'targetEntities' => [],
'thirdPartyDistributionChannels' => []
],
'content' => [
'article' => [
'source' => $used_machine->getUrl(true),
'thumbnail' => $assetId,
'title' => $used_machine->manufacturer .' '. $used_machine->name,
'description' => $used_machine->teaser
]
],
'lifecycleState' => 'PUBLISHED',
'isReshareDisabledByAuthor' => false
];
$headers = [
'Authorization: Bearer '. $this->provider->social_access_token,
'X-Restli-Protocol-Version: 2.0.0',
'Linkedin-Version: '. $this->linkedin_version,
'Content-Type: application/json',
];
$ch = curl_init($postUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$responseHeaders = substr($response, 0, $headerSize);
curl_close($ch);
if ($httpCode === 201) {
// Published successfully
$exported_used_machine->export_action = '';
$exported_used_machine->export_timestamp = date('Y-m-d H:i:s');
// Get post id
$headerLines = explode("\r\n", $responseHeaders);
$xRestliId = null;
foreach ($headerLines as $headerLine) {
if (strpos($headerLine, 'x-restli-id:') === 0) {
$xRestliId = trim(substr($headerLine, 12));
break;
}
}
if ($xRestliId !== null) {
$exported_used_machine->provider_import_id = $response['id'];
$exported_used_machine->save();
} else {
echo "x-restli-id nicht im Header gefunden";
}
$this->log('Post for used machine "'. trim($used_machine->manufacturer .' '. $used_machine->name) .'" on stream of '. $this->provider->linkedin_id .' published (post id: '. $xRestliId .')');
} else {
// Failure publishing post
$this->log('Failure posting used machine "'. trim($used_machine->manufacturer .' '. $used_machine->name) .'" on stream of '. $this->provider->linkedin_id .': '. $response);
$return = false;
}
}
Upvotes: 1
Views: 342
Reputation: 21
Here the working code (Linkedin API Version 202306). See:
// upload image, see https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/images-api?view=li-lms-2023-08&tabs=http#managing-image-asset
$uploadUrl = 'https://api.linkedin.com/rest/images?action=initializeUpload';
$requestData = [
'initializeUploadRequest' => [
'owner' => 'urn:li:person:'. $this->provider->linkedin_id,
],
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $uploadUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $this->provider->social_access_token,
'Linkedin-Version: '. $this->linkedin_version,
'Content-Type: application/json',
]);
$response = curl_exec($ch);
// get asset id
$responseArray = json_decode($response, true);
$assetId = $responseArray['value']['image'];
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 200) {
// upload picture to url received in response
$imagePath = rex_path::media($used_machine->pics[0]);
$uploadUrl = $responseArray['value']['uploadUrl'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $uploadUrl);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($imagePath));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $this->provider->social_access_token,
'Content-Type: '. mime_content_type($imagePath),
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 201) {
$this->log('Image "'. $used_machine->pics[0].'" for used machine "'. trim($used_machine->manufacturer .' '. $used_machine->name) .'" uploded. Asset ID: '. $assetId);
} else {
// failure uploading image
$this->log('Failure uploading image "'. $used_machine->pics[0].'" for used machine "'. trim($used_machine->manufacturer .' '. $used_machine->name) .'". API answer: '. $response);
$return = false;
}
}
// upload post, see https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/posts-api?view=li-lms-2023-08&tabs=http#create-a-post
if($assetId !== '') {
$postUrl = 'https://api.linkedin.com/rest/posts';
$postData = [
'author' => 'urn:li:person:'. $this->provider->linkedin_id,
'commentary' => $used_machine->manufacturer .' '. $used_machine->name .': '. \Sprog\Wildcard::get('d2u_machinery_export_linkedin_details', $this->provider->clang_id),
'contentLandingPage' => $used_machine->getUrl(true),
'visibility' => 'PUBLIC',
'distribution' => [
'feedDistribution' => 'MAIN_FEED',
'targetEntities' => [],
'thirdPartyDistributionChannels' => []
],
'content' => [
'article' => [
'source' => $used_machine->getUrl(true),
'thumbnail' => $assetId,
'title' => $used_machine->manufacturer .' '. $used_machine->name,
'description' => $used_machine->teaser
]
],
'lifecycleState' => 'PUBLISHED',
'isReshareDisabledByAuthor' => false
];
$headers = [
'Authorization: Bearer '. $this->provider->social_access_token,
'X-Restli-Protocol-Version: 2.0.0',
'Linkedin-Version: '. $this->linkedin_version,
'Content-Type: application/json',
];
$ch = curl_init($postUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 201) {
// Published successfully
$exported_used_machine->export_action = '';
$exported_used_machine->export_timestamp = date('Y-m-d H:i:s');
// Get post id
$headerLines = explode("\r\n", $response);
$xRestliId = null;
foreach ($headerLines as $headerLine) {
if (0 === strpos($headerLine, 'x-restli-id:')) {
$xRestliId = trim(substr($headerLine, 12));
break;
}
}
if (null !== $xRestliId) {
$exported_used_machine->provider_import_id = $xRestliId;
}
$exported_used_machine->save();
$this->log('Post for used machine "'. trim($used_machine->manufacturer .' '. $used_machine->name) .'" on stream of '. $this->provider->linkedin_id .' published'. (null !== $xRestliId ? ' (post id: '. $xRestliId .')' : '.'));
} else {
// Failure publishing post
$this->log('Failure posting used machine "'. trim($used_machine->manufacturer .' '. $used_machine->name) .'" on stream of '. $this->provider->linkedin_id .': '. $response);
$return = false;
}
}
Upvotes: 1