17

I'd like to create a message in the #general channel of my Slackspace from within a PHP script. The message should contain text and an image which was created locally on-the-fly.

I've already created an App, generated an bearer token and have managed to create an text-only message also as an image-upload.

But i didn't know how to create both in one message, as the procedure above creates two messages, one with text and another one with the image.

Erik Kalkoken
  • 30,467
  • 8
  • 79
  • 114
T-Regex
  • 179
  • 1
  • 2
  • 8
  • Are you using the Slack API? Because there's a process for that: https://api.slack.com/methods/chat.postMessage – Rentabear Oct 01 '19 at 14:23
  • I use the webhook but processing it with "pure" PHP (because 5.3.3 installed and currently no way to upgrade) . As far as i understand the API docs, you can only add an URL to an existing image. But i need to upload it first and when i do so, it is placed as an own message. – T-Regex Oct 01 '19 at 14:50
  • 3
    I would seriously recommend finding a way to upgrade. You're writing in a language that hasn't had security fixes in 4 years. And it severely limits your ability to use external tools. Since I only have experience working with the API I'm afraid I can't help you further. Hope you find an answer. – Rentabear Oct 01 '19 at 14:56

3 Answers3

25

There are two different approaches on how to post a Slack message with an image.

A. Upload image directly with message

You can upload an image directly to Slack and share it in a channel. Within that request you can also add a comment that will appear as message above the images. This is the easiest approach, however you comment is limited to one string.

API method: files.upload with these arguments:

  • channels: ID of one or multiple channel for the image to appear in
  • initial_comment: Your message

B. Post message with image block / attachment

Alternatively you can add an image to your normal message either as image block or secondary attachment. This only works with a public URL to your image file, so you first need to upload your image to an image hoster (which can be your Slack workspace) to get the public URL.

In our example we will use Slack as image hoster, but you can use any image hoster (e.g. Imgur) even your own webserver, as long as you get a public URL for your image file.

Step 1 - Upload image to Slack

API method: files.upload with no special arguments, but make sure to get the file ID from the response. Don't include the channels argument or the image will be posted visible into those channel.

Step 2 - Create public URL

Next you have to mark the uploaded file as public. Only then will it be accessible through its public_url property

API method: files.sharedPublicURL with the file ID as argument.

Next you need to construct the direct image link from the link to website / permalink_public property of the file.

The website link you get from permalink_public has the format:

https://slack-files.com/{team_id}-{file_id}-{pub_secret}

The direct link to the image has the format:

https://files.slack.com/files-pri/{team_id}-{file_id}/{filename}?pub_secret={pub_secret}

So you just need to extract the pub_secret from permalink_public and you should be able to construct the direct link to the image. The other parameters you can get from your file object.

Step 3 - Send message

Finally compose your message with the image URL either as Image Block or in a secondary attachment and submit it using a method of your choice.

API method: chat.PostMessage or any other method for sending message incl. incoming webhooks.

Answer to OP

If you need to stick with webhooks as it appears from your comments and have no access to the Slack API I would suggest uploading the image to an image hoster (e.g. Imgur) and then use approach B.

See also

Erik Kalkoken
  • 30,467
  • 8
  • 79
  • 114
  • That's great, thanks for you efforts! But, my problem begins with `files.upload` as it will directly post the image on the target channel. I had expected it is first "hidden" somehow, but it didn't. Or do i need to upload the image in a different channel and later just link it from the target message? Or is there some kind of "upload and hide" i miss? – T-Regex Oct 02 '19 at 12:03
  • BTW: Solution A works and may be sufficient for what i'm doing now, but i really looking forward to get solution B also working as it gives much more flexibility (e.g. if i need more than one picture). There is one thing it need to figure out to get solution A fully running: the image is posted under my personal username, but should use the name of the App i build in Slack instead... – T-Regex Oct 02 '19 at 12:20
  • Solution B will only post the image into a channel if you include the `channels` property with `files.upload` – Erik Kalkoken Oct 02 '19 at 12:52
  • If you want the image to appear as being posted by the app you need to have a bot user and use a bot token for posting it. – Erik Kalkoken Oct 02 '19 at 12:53
  • @T-Regex If this answer solved your question please consider marking it as solution. TY! – Erik Kalkoken Oct 02 '19 at 17:34
5

After much tinkering I found that while I could not use the API to create a message and upload an image simultaneously, I can first upload an image and then, with the timestamp returned, use update message to add text to the original message with the image upload.

This is the flow:

1- Use files_upload method to upload an image to my channel (using the channel name)

            response = client.files_upload(
            channels=my_channel_name,
            file=image_path,
            initial_comment='My initial comment'
            )

2- Get the response from the files_upload and extract the channel id and timestamp of the message.

channel_id = response['file']['groups'][0]
ts = response['file']['shares']['private'][channel_id][0]['ts']

3- Use chat update to add text or rich content to the message with the uploaded image:

       response = client.chat_update(
            channel=channel_id,
            text="My Message",
            ts=ts,
            blocks=blocks_list
        )
Annie
  • 71
  • 1
  • 4
  • This method is great because it requires only 2 API calls, and does not require the uploaded image to be public – easd May 14 '21 at 09:56
-1

For those who might still need this.. this gist helped me. Its a quick and easier way using GuzzleHttp.

 use GuzzleHttp\Client;

/**
 * Notes:
 *
 * Tested with guzzlehttp/guzzle version 7.3
 * See https://api.slack.com/methods/files.upload for details on how to generate a token
 *
 */

$fileName = '';
$filePath = '';
$slacktoken = ''; // See https://api.slack.com/tokens; The token will need file.read and file.write permissions

$client = new Client();
$apiUrl = 'https://slack.com/api/files.upload';

$client = new Client();
$request = $client->post( $apiUrl, [
    'headers' => ['Authorization' => 'auth_trusted_header'],
    'multipart' => [
        [
            'name' => 'token',
            'contents' => $slacktoken,
        ],
        [
            'name'     => 'file',
            'contents' => fopen($filePath, 'r'),
            'filename' => $fileName
        ],
        [
            'name' => 'channels',
            'contents' => '#general'
        ],
        [
            'name' => 'initial_comment',
            'contents' => 'File Uploaded'
        ]
    ]
]);

var_dump($request->getBody()->getContents());
emmaakachukwu
  • 515
  • 1
  • 7
  • 16