我try 使用LinkedIns的REST API(https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/share-on-linkedin#create-an-image-share)上传文本、图像和链接.但我没有成功.上传帖子返回错误:ERROR :: /content/article/thumbnail :: Invalid Urn format. Invalid prefix. Urn urn:li:digitalmediaAsset:...

这是我的代码.有什么 idea 或任何提示吗?

// 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;
    }
}

推荐答案

这里是工作代码(LinkedIn API版本202306)

// 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;
    }
}

Php相关问答推荐

如何使用URL链接(mdl)切换选项卡

WordPress:将自定义单选输入字段添加到用户配置文件

Laravel关系-为用户获取属于组织的所有团队

Symfony 6.2 IsGraned具有多个角色

curl_close()未从PHP 8开始写入CURLOPT_COOKIEJAR会话文件

Laravel withOnly不限制查询

为什么从一个页面到另一个页面都找不到 JQuery,因为它们使用相同的 twig 模板?

使用 Spomky Labs JWT 框架中的 verifyWithKey 验证 id_token JWT 的签名需要 30 秒以上

Woocommerce 中为空时隐藏显示变体自定义字段数据

加载 Xdebug PHP 7.4.0 失败

添加或删除优惠券后自动刷新 WooCommerce checkout 表单字段

从 Laravel 机制中排除目录并直接访问该目录

htaccess Rewriterule 无法以任何方式工作

WooCommerce订单支付页面上的附加支付订单按钮

将Shopware 6后端中定义的值导入MultiFilter

在 Symfony 测试中何时使用 TestCase 而不是 KernelTestCase

Xdebug 不会在断点处停止

PHP/Laravel 中的自定义时区

Docker: unixodbc.h 没有这样的文件或目录.已安装 unixodbc-dev 时出现pecl install sqlsrv错误

为什么非贪婪匹配会消耗整个模式,即使后面跟着另一个非贪婪匹配