Uploading and downloading files
MadelineProto provides fully parallelized wrapper methods to upload and download files that support bot API file ids, direct upload by URL and file renaming.
Maximum file size is of 4 GB.
Example bot: downloadRenameBot.php
- download files by URL and rename Telegram files using this async parallelized bot!
- Bot API file IDs
- Uploading & sending files
- Uploading files
- Reusing uploaded files
- Renaming files
- Downloading files
- Getting progress
Sending files
To send photos and documents to someone, use the $MadelineProto->messages->sendMedia method, click on the link for more info.
All files will be uploaded asynchronously and in parallel, 20 chunks at a time for maximum performance (this value can be tweaked in the settings).
The required message
parameter is the caption: it can contain URLs, mentions, bold and italic text, thanks to the parse_mode
parameter, that enables markdown or HTML parsing.
The media
parameter contains the file path and other info about the file.
It can contain lots of various objects, here are the most important:
Security notice
Be careful when calling methods with user-provided parameters: the upload function may be used to access and send any file.
To disable automatic uploads by file name (disabled by default), use the appropriate setting OR upload files manually.
Photos
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\RemoteUrl;
use danog\MadelineProto\BotApiFileId;
use danog\MadelineProto\ParseMode;
$file = new LocalFile('faust.jpg');
// $file = new RemoteUrl('https://example.com/img.jpg');
// ...
// $file can also be a Message, Media, BotApiFileId, ReadableStream object.
$sentMessage = $MadelineProto->sendPhoto(
peer: '@danogentili',
file: $file,
caption: '[This is the caption](https://t.me/MadelineProto)',
parseMode: ParseMode::MARKDOWN
);
Click here » to see the full list of arguments to set set the self-destruction period of the photo, and many more parameters.
Photos as documents
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\RemoteUrl;
use danog\MadelineProto\BotApiFileId;
use danog\MadelineProto\ParseMode;
$file = new LocalFile('faust.jpg');
// $file = new RemoteUrl('https://example.com/img.jpg');
// ...
// $file can also be a Message, Media, BotApiFileId, ReadableStream object.
$sentMessage = $MadelineProto->sendDocumentPhoto(
peer: '@danogentili',
file: $file,
caption: '[This is the caption](https://t.me/MadelineProto)',
parseMode: ParseMode::MARKDOWN
);
Click here » to see the full list of arguments to set set the self-destruction period of the photo, and many more parameters.
Documents
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\RemoteUrl;
use danog\MadelineProto\BotApiFileId;
use danog\MadelineProto\ParseMode;
$file = new LocalFile('faust.txt');
// $file = new RemoteUrl('https://example.com/file.txt');
// ...
// $file can also be a Message, Media, BotApiFileId, ReadableStream object.
$sentMessage = $MadelineProto->sendDocument(
peer: '@danogentili',
file: $file,
caption: '[This is the caption](https://t.me/MadelineProto)',
parseMode: ParseMode::MARKDOWN
);
Click here » to see the full list of arguments to set set the self-destruction period of the document, and many more parameters.
To rename files, provide a Message or another already-uploaded Telegram file object to the file
field.
GIFs
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\RemoteUrl;
use danog\MadelineProto\BotApiFileId;
use danog\MadelineProto\ParseMode;
$file = new LocalFile('gif.mp4');
// $file = new RemoteUrl('https://example.com/gif.mp4');
// ...
// $file can also be a Message, Media, BotApiFileId, ReadableStream object.
$sentMessage = $MadelineProto->sendGif(
peer: '@danogentili',
file: $file,
caption: '[This is the caption](https://t.me/MadelineProto)',
parseMode: ParseMode::MARKDOWN
);
Click here » to see the full list of arguments to set set the self-destruction period of the document, and many more parameters.
MadelineProto will automatically extract the video’s thumbnail, duration, width and height using ffmpeg, if installed.
Videos
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\RemoteUrl;
use danog\MadelineProto\BotApiFileId;
use danog\MadelineProto\ParseMode;
$file = new LocalFile('video.mp4');
// $file = new RemoteUrl('https://example.com/video.mp4');
// ...
// $file can also be a Message, Media, BotApiFileId, ReadableStream object.
$sentMessage = $MadelineProto->sendVideo(
peer: '@danogentili',
file: $file,
caption: '[This is the caption](https://t.me/MadelineProto)',
parseMode: ParseMode::MARKDOWN
);
Click here » to see the full list of arguments to set set the self-destruction period of the document, send round videos, and many more parameters.
MadelineProto will automatically extract the video’s thumbnail, duration, width and height using ffmpeg, if installed.
Music
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\RemoteUrl;
use danog\MadelineProto\BotApiFileId;
use danog\MadelineProto\ParseMode;
$file = new LocalFile('song.mp3');
// $file = new RemoteUrl('https://example.com/song.mp3');
// ...
// $file can also be a Message, Media, BotApiFileId, ReadableStream object.
$sentMessage = $MadelineProto->sendAudio(
peer: '@danogentili',
file: $file,
caption: '[This is the caption](https://t.me/MadelineProto)',
parseMode: ParseMode::MARKDOWN
);
Click here » to see the full list of arguments to set set the self-destruction period of the document, and many more parameters.
MadelineProto will automatically extract the music’s thumbnail and duration using ffmpeg, if installed.
Voice
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\RemoteUrl;
use danog\MadelineProto\BotApiFileId;
use danog\MadelineProto\ParseMode;
$file = new LocalFile('voice.ogg');
// $file = new RemoteUrl('https://example.com/voice.ogg');
// ...
// $file can also be a Message, Media, BotApiFileId, ReadableStream object.
$sentMessage = $MadelineProto->sendVoice(
peer: '@danogentili',
file: $file,
caption: '[This is the caption](https://t.me/MadelineProto)',
parseMode: ParseMode::MARKDOWN
);
Click here » to see the full list of arguments to set set the self-destruction period of the document, and many more parameters.
MadelineProto will automatically extract the voice message’s duration using ffmpeg, if installed.
Stickers
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\RemoteUrl;
use danog\MadelineProto\BotApiFileId;
use danog\MadelineProto\ParseMode;
$file = new LocalFile('sticker.webp');
// $file = new RemoteUrl('https://example.com/sticker.webp');
// ...
// $file can also be a Message, Media, BotApiFileId, ReadableStream object.
$sentMessage = $MadelineProto->sendSticker(
peer: '@danogentili',
file: $file,
mimeType: 'image/webp',
caption: '[This is the caption](https://t.me/MadelineProto)',
parseMode: ParseMode::MARKDOWN
);
Click here » to see the full list of arguments to set set the self-destruction period of the document, and many more parameters.
Uploading files
$MessageMedia = $MadelineProto->messages->uploadMedia([
'media' => [
'_' => 'inputMediaUploadedPhoto',
'file' => 'faust.jpg'
],
]);
The file
can be a file name, a URL, or a file uploaded by someone else (can be used to rename files).
You can also only upload a file, without actually sending it to anyone, storing only the file ID for later usage.
All files will be uploaded asynchronously and in parallel, 20 chunks at a time for maximum performance (this value can be tweaked in the settings).
The $MadelineProto->messages->uploadMedia function is a reduced version of the $MadelineProto->messages->sendMedia, that requires only a media
parameter, with the media to upload (on normal users, the peer
field should be populated with @me
or another value).
The returned MessageMedia object can then be reused to resend the document using sendMedia.
$sentMessage = $MadelineProto->messages->sendMedia([
'peer' => '@danogentili',
'media' => $MessageMedia,
'message' => '[This is the caption](https://t.me/MadelineProto)',
'parse_mode' => 'Markdown'
]);
$MessageMedia
can also be a Message (the media contained in the message will be sent), an Update (the media contained in the message contained in the update will be sent).
Reusing uploaded files
$MadelineProto->messages->uploadMedia
and bot API file IDs do not allow you to modify the type of the file to send: however, MadelineProto provides methods that can generate a file object that can be resent with multiple file types.
$inputFile = $MadelineProto->upload('filename.mp4');
The file name can also be a URL.
More optional parameters are available, check the PHPDOC of the method in your IDE.
You can also upload a file from a stream (this is especially useful, for example, when downloading YouTube videos using youtube-dl
with ffmpeg
and async AMPHP CLI streams):
$inputFile = $MadelineProto->uploadFromStream($stream);
$stream
- PHP resource or async AMPHP stream.
More optional parameters are available, check the PHPDOC of the method in your IDE.
You can also upload files from a callable:
$inputFile = $MadelineProto->uploadFromCallable($callable, $size, $mime);
$callable
:
The callable must accept two parameters: int $offset, int $size
The callable must return a string with the contest of the file at the specified offset and size.
More optional parameters are available, check the PHPDOC of the method in your IDE.
You can also re-use a media received in a message or update, for example in the event handler:
$inputFile = $update;
$inputFile = $message;
The generated $inputFile
can later be reused thusly:
$sentMessage = $MadelineProto->messages->sendMedia([
'peer' => '@danogentili',
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => $inputFile,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => 'video.mp4']
]
],
'message' => '[This is the caption](https://t.me/MadelineProto)',
'parse_mode' => 'Markdown'
]);
$sentMessageVideo = $MadelineProto->messages->sendMedia([
'peer' => '@danogentili',
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => $inputFile,
'attributes' => [
['_' => 'documentAttributeVideo', 'round_message' => false, 'supports_streaming' => true]
]
],
'message' => '[This is the caption](https://t.me/MadelineProto)',
'parse_mode' => 'Markdown'
]);
In this case, we’re reusing the same InputFile to send both a document and a video, without uploading the file twice.
The concept is easy: where you would usually provide a file path, simply provide $inputFile
.
Renaming files
Files can be renamed by simply providing the $Update
with the file to the sendMedia method thusly:
$sentMessage = $MadelineProto->messages->sendMedia([
'peer' => '@danogentili',
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => $Update,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => $newName]
]
],
'message' => '[This is the caption](https://t.me/MadelineProto)',
'parse_mode' => 'Markdown'
]);
Downloading files
There are multiple download methods that allow you to download a file to a directory, to a file or to a stream.
Extracting download info
$info = $MadelineProto->getDownloadInfo($MessageMedia);
$MessageMedia
can be a MessageMedia object or a bot API file ID.
You can also use getDownloadLink to obtain a direct download link for any file up to 4GB.
$info['ext']
- The file extension$info['name']
- The file name, without the extension$info['mime']
- The file mime type$info['size']
- The file size
Getting a download link
To obtain a direct download link for any Telegram file up to 4GB, simply use getDownloadLink
, for example:
<?php
if (!file_exists('madeline.php')) {
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
include 'madeline.php';
$MadelineProto = new \danog\MadelineProto\API('session.madeline');
// For bots
$MadelineProto->botLogin('token');
// For users
//$MadelineProto->start();
$botApiFileId = '...';
$fileName = '...';
$fileSize = 123..;
$mimeType = '...';
$link = $MadelineProto->getDownloadLink($botApiFileId, size: $fileSize, name: $fileName, mime: $mimeType);
Event handler example with bound methods:
use danog\MadelineProto\SimpleEventHandler;
use danog\MadelineProto\EventHandler\Filter\FilterCommand;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\SimpleFilter\Incoming;
class MyEventHandler extends SimpleEventHandler
{
/**
* Gets a download link for any file up to 4GB!
*/
#[FilterCommand('dl')]
public function downloadLink(Incoming&Message $message): void
{
$reply = $message->getReply(Message::class);
if (!$reply?->media) {
$message->reply("This command must reply to a media message!");
return;
}
$reply->reply("Download link: ".$reply->media->getDownloadLink());
}
}
MyEventHandler::startAndLoop('bot.madeline')
$botApiFileId
can be a MessageMedia object or a bot API file ID (files up to 4GB are supported!).
This method will work automatically only when running via web (apache/php-fpm).
The generated download $link
will point to your own server, and the link will stream files directly to the browser (no temporary files will be created, 0 disk space will be used).
Getting a download link (CLI bots)
Only if running via CLI (or if URL rewriting is enabled on web), a second parameter must be provided with a URL to a download script hosted on a php-fpm/apache instance on the same machine:
<?php
if (!file_exists('madeline.php')) {
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
include 'madeline.php';
$MadelineProto = new \danog\MadelineProto\API('session.madeline');
// For bots
$MadelineProto->botLogin('token');
// For users
//$MadelineProto->start();
$botApiFileId = '...';
$fileName = '...';
$fileSize = 123..;
$mimeType = '...';
$link = $MadelineProto->getDownloadLink($botApiFileId, 'https://yourhost.com/dl.php', size: $fileSize, name: $fileName, mime: $mimeType);
Event handler example with bound methods:
use danog\MadelineProto\SimpleEventHandler;
use danog\MadelineProto\EventHandler\Filter\FilterCommand;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\SimpleFilter\Incoming;
class MyEventHandler extends SimpleEventHandler
{
/**
* Gets a download link for any file up to 4GB!
*/
#[FilterCommand('dl')]
public function downloadLink(Incoming&Message $message): void
{
$reply = $message->getReply(Message::class);
if (!$reply?->media) {
$message->reply("This command must reply to a media message!");
return;
}
$reply->reply("Download link: ".$reply->media->getDownloadLink('https://yourhost.com/dl.php'));
}
}
MyEventHandler::startAndLoop('bot.madeline')
You can also pass your custom download link in the Files settings, instead.
The dl.php script must have the following content:
<?php
if (!file_exists('madeline.php')) {
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
include 'madeline.php';
\danog\MadelineProto\API::downloadServer('session.madeline');
Note that session.madeline
must be logged into exactly the same user/bot used by the CLI userbot/bot.
To login the first time, simple open dl.php?login=1
in your browser: if the session is not logged in, a login prompt will be shown, otherwise the user/bot ID will be displayed.
The link will stream files directly to the browser (no temporary files will be created, 0 disk space will be used).
Downloading profile pictures
$info = $MadelineProto->getPropicInfo($Update);
$Update
can be a Message object, an Update, or any value supported by getInfo.
The result will be a Photo object.
Download to directory
$output_file_name = $MadelineProto->downloadToDir($MessageMedia, '/tmp/');
This downloads the given file to /tmp
, and returns the full generated file path.
Note: if downloading files that will be re-downloaded by the user, use downloadToBrowser, instead: downloadToBrowser will avoid the creation of temporary files, streaming the file directly to the user.
You can also use getDownloadLink to obtain a direct download link for any file up to 4GB.
$MessageMedia
can be either a Message, an Update, a MessageMedia object, or a bot API file ID.
Download to file
$output_file_name = $MadelineProto->downloadToFile($MessageMedia, '/tmp/myname.mp4');
Note: if downloading files that will be re-downloaded by the user, use downloadToBrowser, instead: downloadToBrowser will avoid the creation of temporary files, streaming the file directly to the user.
You can also use getDownloadLink to obtain a direct download link for any file up to 4GB.
This downloads the given file to /tmp/myname.mp4
, and returns the full file path.
$MessageMedia
can be either a Message, an Update, a MessageMedia object, or a bot API file ID.
Download to stream
$MadelineProto->downloadToStream($MessageMedia, $stream);
This downloads the given file to the given resource or async AMPHP stream, the latter is especially useful for building an async HTTP file server with http-server.
$MessageMedia
can be either a Message, an Update, a MessageMedia object, or a bot API file ID.
You can also use downloadToReturnedStream
, which returns an amphp ReadableStream
, instead:
$stream = $MadelineProto->downloadToReturnedStream($MessageMedia);
Download to callback
$MadelineProto->downloadToCallable($MessageMedia, $callable);
This downloads the given file to the callable. The callable must accept two parameters: string $payload, int $offset
The callable will be called (possibly out of order, depending on the value of the $seekable
(see PHPDOC)). The callable should return the number of written bytes.
$MessageMedia
can be either a Message, an Update, a MessageMedia object, or a bot API file ID.
Download to http-server
$MadelineProto->downloadToResponse($MessageMedia, $request, $cb);
This downloads the given file, replying to the specified async http-server request.
Automatically supports HEAD requests and content-ranges for parallel and resumed downloads.
$MessageMedia
can be either a Message, an Update, a MessageMedia object, or a bot API file ID.
$request
is the Request object returned by http-server.
$cb
is an optional parameter can be a callback for download progress, but it shouldn’t be used, the new FileCallback should be used instead
Download to browser
$MadelineProto->downloadToBrowser($MessageMedia, $cb);
You can also use getDownloadLink to obtain a direct download link for any file up to 4GB.
This downloads the given file to the browser, sending also information about the file’s type and size. Automatically supports HEAD requests and content-ranges for parallel and resumed downloads.
$MessageMedia
can be either a Message, an Update, a MessageMedia object, or a bot API file ID.
$cb
is an optional parameter can be a callback for download progress, but it shouldn’t be used, the new FileCallback should be used instead
Getting progress
To get the upload/download progress in real-time, use the \danog\MadelineProto\FileCallback
class:
$peer = '@danogentili';
$sentMessage = $MadelineProto->messages->sendMedia([
'peer' => $peer,
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => new \danog\MadelineProto\FileCallback(
'video.mp4',
function ($progress, $speed, $time) use ($MadelineProto, $peer) {
try {
$MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => "Upload progress: $progress%\nSpeed: $speed mbps\nTime elapsed since start: $time"]);
} catch (\Throwable $e) {}
}
),
'attributes' => [
['_' => 'documentAttributeVideo', 'round_message' => false, 'supports_streaming' => true]
]
],
'message' => '[This is the caption](https://t.me/MadelineProto)',
'parse_mode' => 'Markdown'
]);
$output_file_name = $MadelineProto->downloadToFile(
$sentMessage,
new \danog\MadelineProto\FileCallback(
'/tmp/myname.mp4',
function ($progress, $speed, $time) use ($MadelineProto, $peer) {
try {
$MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => "Download progress: $progress%\nSpeed: $speed mbps\nTime elapsed since start: $time"]);
} catch (\Throwable $e) {}
}
)
);
This will send the file video.mp4
to @danogentili: while uploading, he will receive progress messages Upload progress: 24%
until the upload is complete; while downloading, he will receive progress messages Download progress: 34%
until the download is complete.
You can also add two more parameters $speed, $time
to the signature of the method to get a partial upload speed in mbps, along with the time elapsed since the start of the download.
A FileCallback object can be provided to uploadMedia
, sendMedia
, uploadProfilePicture
, upload
, upload_encrypted
, download_to_*
: the first parameter to its constructor must be the file path/object that is usually accepted by the function, the second must be a callable function or object.
You can also write your own callback class, just implement \danog\MadelineProto\FileCallbackInterface
:
class MyCallback implements \danog\MadelineProto\FileCallbackInterface
{
private $file;
private $peer;
private $MadelineProto;
public function __construct($file, $peer, $MadelineProto)
{
$this->file = $file;
$this->peer = $peer;
$this->MadelineProto = $MadelineProto;
}
public function getFile()
{
return $this->file;
}
public function __invoke($progress, $speed, $time)
{
$this->MadelineProto->messages->sendMessage(['peer' => $this->peer, 'message' => 'Progress: '.$progress.'%']);
}
}
$peer = '@danogentili';
$sentMessage = $MadelineProto->messages->sendMedia([
'peer' => $peer,
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => new MyCallback('video.mp4', $peer, $MadelineProto),
'attributes' => [
['_' => 'documentAttributeVideo', 'round_message' => false, 'supports_streaming' => true]
]
],
'message' => '[This is the caption](https://t.me/MadelineProto)',
'parse_mode' => 'Markdown'
]);
$output_file_name = $MadelineProto->downloadToFile(
$sentMessage,
new MyCallback('/tmp/myname.mp4', $peer, $MadelineProto)
);
Bot API file IDs
$MessageMedia
can even be a bot API file ID, generated by the bot API, or by MadelineProto:
Actual MessageMedia objects can also be converted to bot API file IDs like this:
$botAPI_file = $MadelineProto->MTProtoToBotAPI($MessageMedia);
$botAPI_file
now contains a bot API message, to extract the file ID from it use the following code:
foreach (['audio', 'document', 'photo', 'sticker', 'video', 'voice', 'video_note'] as $type) {
if (isset($botAPI_file[$type]) && is_array($botAPI_file[$type])) {
$method = $type;
}
}
$result['file_type'] = $method;
if ($result['file_type'] == 'photo') {
$result['file_size'] = $botAPI_file[$method][0]['file_size'];
if (isset($botAPI_file[$method][0]['file_name'])) {
$result['file_name'] = $botAPI_file[$method][0]['file_name'];
$result['file_id'] = $botAPI_file[$method][0]['file_id'];
}
} else {
if (isset($botAPI_file[$method]['file_name'])) {
$result['file_name'] = $botAPI_file[$method]['file_name'];
}
if (isset($botAPI_file[$method]['file_size'])) {
$result['file_size'] = $botAPI_file[$method]['file_size'];
}
if (isset($botAPI_file[$method]['mime_type'])) {
$result['mime_type'] = $botAPI_file[$method]['mime_type'];
}
$result['file_id'] = $botAPI_file[$method]['file_id'];
}
if (!isset($result['mime_type'])) {
$result['mime_type'] = 'application/octet-stream';
}
if (!isset($result['file_name'])) {
$result['file_name'] = $result['file_id'].($method === 'sticker' ? '.webp' : '');
}
$result['file_id']
- Bot API file ID$result['mime_type']
- Mime type$result['file_type']
- File type: voice, video, video_note (round video), music, video, photo, sticker or document$result['file_size']
- File size$result['file_name']
- File name