Bugfixes and added support for downloading only specified ranges of a file
This commit is contained in:
parent
7343ae83cf
commit
3b8cc9d5ee
@ -341,7 +341,7 @@ The first parameter of these functions must always be a [messageMediaPhoto](http
|
||||
$output_file_name = $MadelineProto->download_to_dir($message_media, '/tmp/dldir');
|
||||
$custom_output_file_name = $MadelineProto->download_to_file($message_media, '/tmp/dldir/customname.ext');
|
||||
$stream = fopen('php://output', 'w'); // Stream to browser like with echo
|
||||
$MadelineProto->download_to_stream($message_media, $stream);
|
||||
$MadelineProto->download_to_stream($message_media, $stream, $cb, $offset, $endoffset); // offset and endoffset are optional parameters that specify the byte from which to start downloading and the byte where to stop downloading (the latter non-inclusive), if not specified default to 0 and the size of the file
|
||||
```
|
||||
|
||||
|
||||
|
@ -1,7 +1,3 @@
|
||||
---
|
||||
title: MadelineProto documentation
|
||||
description: PHP implementation of telegram's MTProto protocol
|
||||
---
|
||||
# MadelineProto
|
||||
[![StyleCI](https://styleci.io/repos/61838413/shield)](https://styleci.io/repos/61838413)
|
||||
[![Build Status](https://travis-ci.org/danog/MadelineProto.svg?branch=master)](https://travis-ci.org/danog/MadelineProto)
|
||||
@ -345,7 +341,7 @@ The first parameter of these functions must always be a [messageMediaPhoto](http
|
||||
$output_file_name = $MadelineProto->download_to_dir($message_media, '/tmp/dldir');
|
||||
$custom_output_file_name = $MadelineProto->download_to_file($message_media, '/tmp/dldir/customname.ext');
|
||||
$stream = fopen('php://output', 'w'); // Stream to browser like with echo
|
||||
$MadelineProto->download_to_stream($message_media, $stream);
|
||||
$MadelineProto->download_to_stream($message_media, $stream, $cb, $offset, $endoffset); // offset and endoffset are optional parameters that specify the byte from which to start downloading and the byte where to stop downloading (the latter non-inclusive), if not specified default to 0 and the size of the file
|
||||
```
|
||||
|
||||
|
||||
|
@ -235,7 +235,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
{
|
||||
foreach ($this->datacenter->sockets as $id => &$socket) {
|
||||
\danog\MadelineProto\Logger::log('Resetting session id and seq_no in DC '.$id.'...');
|
||||
$socket->session_id = \phpseclib\Crypt\Random::string(8);
|
||||
$socket->session_id = \danog\MadelineProto\Tools::random(8);
|
||||
$socket->seq_no = 0;
|
||||
$socket->incoming_messages = [];
|
||||
$socket->outgoing_messages = [];
|
||||
@ -275,7 +275,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
public function init_authorization()
|
||||
{
|
||||
if ($this->datacenter->session_id == null) {
|
||||
$this->datacenter->session_id = \phpseclib\Crypt\Random::string(8);
|
||||
$this->datacenter->session_id = \danog\MadelineProto\Tools::random(8);
|
||||
}
|
||||
if ($this->datacenter->temp_auth_key == null || $this->datacenter->auth_key == null) {
|
||||
if ($this->datacenter->auth_key == null) {
|
||||
|
@ -43,7 +43,7 @@ trait AuthKeyHandler
|
||||
* Vector long $server_public_key_fingerprints : This is a list of public RSA key fingerprints
|
||||
* ]
|
||||
*/
|
||||
$nonce = \phpseclib\Crypt\Random::string(16);
|
||||
$nonce = \danog\MadelineProto\Tools::random(16);
|
||||
$ResPQ = $this->method_call('req_pq',
|
||||
[
|
||||
'nonce' => $nonce,
|
||||
@ -103,7 +103,7 @@ trait AuthKeyHandler
|
||||
$p_bytes = \danog\PHP\Struct::pack('>I', (string) $p);
|
||||
$q_bytes = \danog\PHP\Struct::pack('>I', (string) $q);
|
||||
|
||||
$new_nonce = \phpseclib\Crypt\Random::string(32);
|
||||
$new_nonce = \danog\MadelineProto\Tools::random(32);
|
||||
|
||||
$data_unserialized = [
|
||||
'pq' => $pq_bytes,
|
||||
@ -121,7 +121,7 @@ trait AuthKeyHandler
|
||||
* Encrypt serialized object
|
||||
*/
|
||||
$sha_digest = sha1($p_q_inner_data, true);
|
||||
$random_bytes = \phpseclib\Crypt\Random::string(255 - strlen($p_q_inner_data) - strlen($sha_digest));
|
||||
$random_bytes = \danog\MadelineProto\Tools::random(255 - strlen($p_q_inner_data) - strlen($sha_digest));
|
||||
$to_encrypt = $sha_digest.$p_q_inner_data.$random_bytes;
|
||||
$encrypted_data = $this->key->encrypt($to_encrypt);
|
||||
|
||||
@ -316,7 +316,7 @@ trait AuthKeyHandler
|
||||
|
||||
foreach ($this->range(0, $this->settings['max_tries']['authorization']) as $retry_id) {
|
||||
\danog\MadelineProto\Logger::log('Generating b...');
|
||||
$b = new \phpseclib\Math\BigInteger(\phpseclib\Crypt\Random::string(256), 256);
|
||||
$b = new \phpseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
|
||||
\danog\MadelineProto\Logger::log('Generating g_b...');
|
||||
$g_b = $g->powMod($b, $dh_prime);
|
||||
|
||||
@ -362,7 +362,7 @@ trait AuthKeyHandler
|
||||
* encrypt client_DH_inner_data
|
||||
*/
|
||||
$data_with_sha = sha1($data, true).$data;
|
||||
$data_with_sha_padded = $data_with_sha.\phpseclib\Crypt\Random::string($this->posmod(-strlen($data_with_sha), 16));
|
||||
$data_with_sha_padded = $data_with_sha.\danog\MadelineProto\Tools::random($this->posmod(-strlen($data_with_sha), 16));
|
||||
$encrypted_data = $this->ige_encrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv);
|
||||
|
||||
\danog\MadelineProto\Logger::log('Executing set_client_DH_params...');
|
||||
@ -481,7 +481,7 @@ trait AuthKeyHandler
|
||||
public function bind_temp_auth_key($expires_in)
|
||||
{
|
||||
\danog\MadelineProto\Logger::log('Binding authorization keys...');
|
||||
$nonce = \danog\PHP\Struct::unpack('<q', \phpseclib\Crypt\Random::string(8))[0];
|
||||
$nonce = \danog\PHP\Struct::unpack('<q', \danog\MadelineProto\Tools::random(8))[0];
|
||||
$expires_at = time() + $expires_in;
|
||||
$temp_auth_key_id = \danog\PHP\Struct::unpack('<q', $this->datacenter->temp_auth_key['id'])[0];
|
||||
$perm_auth_key_id = \danog\PHP\Struct::unpack('<q', $this->datacenter->auth_key['id'])[0];
|
||||
@ -499,9 +499,9 @@ trait AuthKeyHandler
|
||||
|
||||
$message_id = \danog\PHP\Struct::pack('<Q', $int_message_id);
|
||||
$seq_no = 0;
|
||||
$encrypted_data = \phpseclib\Crypt\Random::string(16).$message_id.\danog\PHP\Struct::pack('<II', $seq_no, strlen($message_data)).$message_data;
|
||||
$encrypted_data = \danog\MadelineProto\Tools::random(16).$message_id.\danog\PHP\Struct::pack('<II', $seq_no, strlen($message_data)).$message_data;
|
||||
$message_key = substr(sha1($encrypted_data, true), -16);
|
||||
$padding = \phpseclib\Crypt\Random::string($this->posmod(-strlen($encrypted_data), 16));
|
||||
$padding = \danog\MadelineProto\Tools::random($this->posmod(-strlen($encrypted_data), 16));
|
||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->datacenter->auth_key['auth_key']);
|
||||
$encrypted_message = $this->datacenter->auth_key['id'].$message_key.$this->ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv);
|
||||
|
||||
|
@ -37,7 +37,7 @@ trait MessageHandler
|
||||
$seq_no = $this->generate_seq_no($content_related);
|
||||
$encrypted_data = \danog\PHP\Struct::pack('<q', $this->datacenter->temp_auth_key['server_salt']).$this->datacenter->session_id.$message_id.\danog\PHP\Struct::pack('<II', $seq_no, strlen($message_data)).$message_data;
|
||||
$message_key = substr(sha1($encrypted_data, true), -16);
|
||||
$padding = \phpseclib\Crypt\Random::string($this->posmod(-strlen($encrypted_data), 16));
|
||||
$padding = \danog\MadelineProto\Tools::random($this->posmod(-strlen($encrypted_data), 16));
|
||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->datacenter->temp_auth_key['auth_key']);
|
||||
$message = $this->datacenter->temp_auth_key['id'].$message_key.$this->ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv);
|
||||
$this->datacenter->outgoing_messages[$int_message_id]['seq_no'] = $seq_no;
|
||||
|
@ -25,12 +25,18 @@ trait UpdateHandler
|
||||
|
||||
public function get_updates_update_handler($update)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
$this->updates[$this->updates_key++] = $update;
|
||||
//\danog\MadelineProto\Logger::log('Stored ', $update);
|
||||
}
|
||||
|
||||
public function get_updates($params = [])
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
$time = microtime(true);
|
||||
$this->force_get_updates_difference();
|
||||
$default_params = ['offset' => 0, 'limit' => null, 'timeout' => 0];
|
||||
@ -75,6 +81,9 @@ trait UpdateHandler
|
||||
|
||||
public function get_channel_difference($channel)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
if (!$this->get_channel_state($channel)['sync_loading']) {
|
||||
$this->get_channel_state($channel)['sync_loading'] = true;
|
||||
$this->get_channel_state($channel)['pending_pts_updates'] = [];
|
||||
@ -133,6 +142,9 @@ trait UpdateHandler
|
||||
|
||||
public function get_updates_difference()
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
if (!$this->get_update_state()['sync_loading']) {
|
||||
$this->get_update_state()['sync_loading'] = true;
|
||||
$this->get_update_state()['pending_pts_updates'] = [];
|
||||
@ -313,6 +325,9 @@ trait UpdateHandler
|
||||
|
||||
public function pop_pending_seq_update()
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
$next_seq = $this->get_update_state()['seq'] + 1;
|
||||
if (empty($this->get_update_state()['pending_seq_updates'][$next_seq]['updates'])) {
|
||||
return false;
|
||||
@ -332,6 +347,9 @@ trait UpdateHandler
|
||||
|
||||
public function pop_pending_pts_update($channel_id)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
if ($channel_id === false) {
|
||||
$cur_state = &$this->get_update_state();
|
||||
} else {
|
||||
@ -363,6 +381,9 @@ trait UpdateHandler
|
||||
|
||||
public function handle_multiple_update($updates, $options = [], $channel = false)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
if ($channel === false) {
|
||||
foreach ($updates as $update) {
|
||||
switch ($update['_']) {
|
||||
@ -383,6 +404,9 @@ trait UpdateHandler
|
||||
|
||||
public function handle_update_messages($messages, $channel = false)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
foreach ($messages as $message) {
|
||||
$this->save_update(['_' => $channel == false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => $channel == false ? $this->get_update_state()['pts'] : $this->get_channel_state($channel)['pts'], 'pts_count' => 0]);
|
||||
}
|
||||
|
@ -252,16 +252,16 @@ trait TL
|
||||
if ($current_argument['name'] == 'random_id') {
|
||||
switch ($current_argument['type']) {
|
||||
case 'long':
|
||||
$serialized .= \phpseclib\Crypt\Random::string(8);
|
||||
$serialized .= \danog\MadelineProto\Tools::random(8);
|
||||
continue 2;
|
||||
case 'int':
|
||||
$serialized .= \phpseclib\Crypt\Random::string(4);
|
||||
$serialized .= \danog\MadelineProto\Tools::random(4);
|
||||
continue 2;
|
||||
case 'Vector t':
|
||||
if (isset($arguments['id'])) {
|
||||
$serialized .= \danog\PHP\Struct::pack('<i', $this->constructors->find_by_predicate('vector')['id']);
|
||||
$serialized .= \danog\PHP\Struct::pack('<i', count($arguments['id']));
|
||||
$serialized .= \phpseclib\Crypt\Random::string(8 * count($arguments['id']));
|
||||
$serialized .= \danog\MadelineProto\Tools::random(8 * count($arguments['id']));
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,10 @@ namespace danog\MadelineProto;
|
||||
*/
|
||||
trait Tools
|
||||
{
|
||||
public static function random($length) {
|
||||
if ($length === 0) return '';
|
||||
return \danog\MadelineProto\Tools::random($length);
|
||||
}
|
||||
/**
|
||||
* posmod(numeric,numeric) : numeric
|
||||
* Works just like the % (modulus) operator, only returns always a postive number.
|
||||
|
@ -424,7 +424,7 @@ trait FilesHandler
|
||||
$part_num = 0;
|
||||
$method = $file_size > 10 * 1024 * 1024 ? 'upload.saveBigFilePart' : 'upload.saveFilePart';
|
||||
$constructor = $file_size > 10 * 1024 * 1024 ? 'inputFileBig' : 'inputFile';
|
||||
$file_id = \danog\PHP\Struct::unpack('<q', \phpseclib\Crypt\Random::string(8))[0];
|
||||
$file_id = \danog\PHP\Struct::unpack('<q', \danog\MadelineProto\Tools::random(8))[0];
|
||||
$f = fopen($file, 'r');
|
||||
fseek($f, 0);
|
||||
while (ftell($f) !== $file_size) {
|
||||
@ -451,6 +451,7 @@ trait FilesHandler
|
||||
|
||||
public function get_download_info($message_media)
|
||||
{
|
||||
if (!isset($message_media['_']) && isset($message_media['InputFileLocation']) && isset($message_media['size'])) return $message_media;
|
||||
$res = [];
|
||||
switch ($message_media['_']) {
|
||||
case 'messageMediaPhoto':
|
||||
@ -460,6 +461,7 @@ trait FilesHandler
|
||||
$res['name'] = $photo['location']['volume_id'].'_'.$photo['location']['local_id'];
|
||||
$res['size'] = $photo['size'];
|
||||
$res['InputFileLocation'] = ['_' => 'inputFileLocation', 'volume_id' => $photo['location']['volume_id'], 'local_id' => $photo['location']['local_id'], 'secret' => $photo['location']['secret']];
|
||||
$res['mime'] = 'image/jpeg';
|
||||
|
||||
return $res;
|
||||
|
||||
@ -492,7 +494,7 @@ trait FilesHandler
|
||||
}
|
||||
$res['name'] .= '_'.$message_media['document']['id'];
|
||||
$res['size'] = $message_media['document']['size'];
|
||||
|
||||
$res['mime'] = $message_media['document']['mime_type'];
|
||||
$res['InputFileLocation'] = ['_' => 'inputDocumentFileLocation', 'id' => $message_media['document']['id'], 'access_hash' => $message_media['document']['access_hash'], 'version' => $message_media['document']['version']];
|
||||
|
||||
return $res;
|
||||
@ -506,7 +508,7 @@ trait FilesHandler
|
||||
{
|
||||
$info = $this->get_download_info($message_media);
|
||||
|
||||
return $this->download_to_file($message_media, $dir.'/'.$info['name'].$info['ext'], $cb);
|
||||
return $this->download_to_file($info, $dir.'/'.$info['name'].$info['ext'], $cb);
|
||||
}
|
||||
|
||||
public function download_to_file($message_media, $file, $cb = null)
|
||||
@ -515,13 +517,15 @@ trait FilesHandler
|
||||
touch($file);
|
||||
}
|
||||
$stream = fopen($file, 'w');
|
||||
fseek($stream, filesize($file));
|
||||
$this->download_to_stream($message_media, $stream, $cb);
|
||||
$info = $this->get_download_info($message_media);
|
||||
|
||||
|
||||
$this->download_to_stream($info, $stream, $cb, filesize($file), $info['size']);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function download_to_stream($message_media, $stream, $cb = null)
|
||||
public function download_to_stream($message_media, $stream, $cb = null, $offset = 0, $end = -1)
|
||||
{
|
||||
if ($cb === null) {
|
||||
$cb = function ($percent) {
|
||||
@ -529,10 +533,17 @@ trait FilesHandler
|
||||
};
|
||||
}
|
||||
$info = $this->get_download_info($message_media);
|
||||
$offset = ftell($stream);
|
||||
if ($end === -1) $end = $info['size'];
|
||||
if (stream_get_meta_data($stream)['seekable']) fseek($stream, $offset);
|
||||
$size = $end - $offset;
|
||||
$part_size = 512 * 1024;
|
||||
while (fwrite($stream, $this->API->method_call('upload.getFile', ['location' => $info['InputFileLocation'], 'offset' => $offset += $part_size, 'limit' => $part_size], null, true)['bytes']) != false) {
|
||||
$cb(ftell($stream) * 100 / $info['size']);
|
||||
$percent = 0;
|
||||
while ($percent < 100) {
|
||||
$real_part_size = ($offset + $part_size > $end) ? $part_size - (($offset + $part_size) - $end) : $part_size;
|
||||
\danog\MadelineProto\Logger::log($real_part_size, $offset);
|
||||
fwrite($stream, $this->API->method_call('upload.getFile', ['location' => $info['InputFileLocation'], 'offset' => $offset, 'limit' => $real_part_size], null, true)['bytes']);
|
||||
\danog\MadelineProto\Logger::log($offset, $size, ftell($stream));
|
||||
$cb($percent = ($offset += $real_part_size) * 100 / $size);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user