php-telegram-bot / core

PHP Telegram Bot based on the official Telegram Bot API
MIT License
3.88k stars 954 forks source link

Files are not getting stored or maybe I can't locate them... #221

Closed progS1m closed 8 years ago

progS1m commented 8 years ago

I've a problem that I can't see any files, photos, etc sent from my mobile phone.

To figure out where the files should be located I used this code in hook.php echo $telegram->getUploadPath();

Output from Browser: /var/www/website.tld/mybot/php-telegram-bot/src/../Upload

So the location for uploaded files should be there /var/www/website.tld/mybot/php-telegram-bot/src/Upload right?

All the folder permissions should be correct. Webserver (Nginx) runs as www-data.

# ls -l
total 1900
-rwxrwxr--  1 root www-data  120414 Jun  8 20:35 mybot_debug.log
-rwxrwxr--  1 root www-data    7070 Jun  8 20:35 mybot_error.log
-rwxrwxr--  1 root www-data   25560 Jun  8 20:37 mybot_update.log
drwxrwxr--  2 root www-data    4096 Jun  6 22:34 commands
-rwxrwxr--  1 root www-data    1049 Jun  7 19:34 composer.json
-rwxrwxr--  1 root www-data   41755 Jun  5 20:27 composer.lock
-rwxrwxr--  1 root www-data 1640247 Jun  5 20:44 composer.phar
-rwxrwxr--  1 root www-data    1589 Jun  5 20:27 CONTRIBUTING.md
-rwxrwxr--  1 root www-data     712 Jun  5 20:27 CREDITS
drwxrwxr--  2 root www-data    4096 Jun  5 20:27 doc
drwxrwxr--  3 root www-data    4096 Jun  5 20:27 examples
-rwxrwxr--  1 root www-data    3561 Jun  8 20:35 hook.php
-rwxrwxr--  1 root www-data    1175 Jun  5 20:27 LICENSE.md
-rwxrwxr--  1 root www-data    4149 Jun  5 20:27 phpcs.xml
-rwxrwxr--  1 root www-data    1519 Jun  5 20:27 phpunit.xml.dist
-rwxrwxr--  1 root www-data   17323 Jun  5 20:27 README.md
-rwxrwxr--  1 root www-data     650 Jun  5 22:38 set.php
drwxrwxr--  5 root www-data    4096 Jun  5 20:27 src
drwxrwxr--  3 root www-data    4096 Jun  5 20:27 tests
drwxrwxr--  2 root www-data    4096 Jun  8 20:30 Upload
drwxrwxr--  2 root www-data    4096 Jun  5 20:27 utils
drwxrwxr-- 13 root www-data    4096 Jun  7 19:34 vendor'
root@30393:/var/www/website.tld/mybot/php-telegram-bot/src# ls -l
total 136
-rwxrwxr-- 1 root www-data  2600 Jun  5 20:27 BotanDB.php
-rwxrwxr-- 1 root www-data  5665 Jun  5 20:27 Botan.php
drwxrwxr-- 5 root www-data  4096 Jun  5 20:27 Commands
-rwxrwxr-- 1 root www-data  5375 Jun  5 20:27 ConversationDB.php
-rwxrwxr-- 1 root www-data  5402 Jun  5 20:27 Conversation.php
-rwxrwxr-- 1 root www-data 37347 Jun  5 20:27 DB.php
drwxrwxr-- 2 root www-data  4096 Jun  5 20:27 Entities
drwxrwxr-- 2 root www-data  4096 Jun  5 20:27 Exception
-rwxrwxr-- 1 root www-data 20800 Jun  5 20:27 Request.php
-rwxrwxr-- 1 root www-data  5147 Jun  7 21:50 TelegramLog.php
-rwxrwxr-- 1 root www-data 18623 Jun  5 20:27 Telegram.php
drwxrwxr-- 2 root www-data  4096 Jun  8 21:10 Upload

In my update.log I can see that a new entry is getting generated when sending a file from mobile phone. Per example audio looks like this: {"update_id":86454387, "message":{"message_id":601,"from":{"id":123456789,"first_name":"myFirstname","last_name":"myLastName"},"chat":{"id":123456789,"first_name":"myFirstname","last_name":"myLastName","type":"private"},"date":1465411058,"voice":{"duration":1,"mime_type":"audio\/ogg","file_id":"AwADBAADBQAD3QozDt94YZV9NlHoAg","file_size":2750}}}

When I try to debug with the setCustomInput function and call the hook.php via browser I don't get an error.

No related log entry in debug.log or error.log is visible.

Has someone an idea what could cause this issue? Thanks for help!

PHP Version: PHP 5.6.20-0+deb8u1 (cli) (built: Apr 27 2016 11:26:05) Copyright (c) 1997-2016 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

php-telegram-bot version: 0.33

noplanman commented 8 years ago

The uploaded files aren't saved anywhere automatically at the moment...

What you could do in the meantime, is create a custom command, say /upload, and then save the uploaded file then.

I'll put together the command for you to use, stay tuned!

If you feel like exploring a bit in the meantime, take a look at the SurveyCommand.php file and look here how to save an uploaded file: https://github.com/akalongman/php-telegram-bot/issues/123#issuecomment-224523310

noplanman commented 8 years ago

@MBoretto @jacklul @akalongman Should every file that gets uploaded to the bot automatically be saved to the Upload folder? Would make sense, right?

At the moment the Upload folder isn't even used!

jacklul commented 8 years ago

Not by default. I noticed on my bot there is a lot of people who just try to send files to the bot, most likely viruses and stuff.

progS1m commented 8 years ago

Mhm it shouldn't be activated by default. My bot I develop is for a game (mrX). Only user with a specific /join 'token' can join respectively will be able to use all commands. For some challenges in the game they need to upload pictures, which an admin later analyse manually and if challenge passed they get credits.

noplanman commented 8 years ago

@jacklul You're absolutely right, by default isn't a good idea. We could add a setting for those people who would want that, or at least a helper to make file downloads less painful.

@xtrahost Voilà, save as UploadCommand.php in your custom commands folder. Being a UserCommand, anyone can use it! So you might want to change it to an AdminCommand.

<?php
/**
 * This file is part of the TelegramBot package.
 *
 * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Longman\TelegramBot\Commands\UserCommands;

use Longman\TelegramBot\Request;
use Longman\TelegramBot\Conversation;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\ForceReply;
use Longman\TelegramBot\Entities\ReplyKeyboardHide;
use Longman\TelegramBot\TelegramLog;

/**
 * User "/upload" command
 */
class UploadCommand extends UserCommand
{
    /**#@+
     * {@inheritdoc}
     */
    protected $name = 'upload';
    protected $description = 'Upload and save files';
    protected $usage = '/upload';
    protected $version = '0.0.1';
    protected $need_mysql = true;
    /**#@-*/

    /**
     * Conversation Object
     *
     * @var Longman\TelegramBot\Conversation
     */
    protected $conversation;

    /**
     * {@inheritdoc}
     */
    public function execute()
    {
        $message = $this->getMessage();

        $chat = $message->getChat();
        $user = $message->getFrom();

        $chat_id = $chat->getId();
        $user_id = $user->getId();

        //Preparing Response
        $data = [
            'chat_id'      => $chat_id,
            'reply_markup' => new ReplyKeyBoardHide(['selective' => true]),
        ];

        if ($chat->isGroupChat() || $chat->isSuperGroup()) {
            //reply to message id is applied by default
            $data['reply_to_message_id'] = $message->getMessageId();
            //Force reply is applied by default to so can work with privacy on
            $data['reply_markup'] = new ForceReply([ 'selective' => true]);
        }

        //Conversation start
        $this->conversation = new Conversation($user_id, $chat_id, $this->getName());

        if (in_array($message->getType(), ['audio', 'document', 'photo', 'video', 'voice'])) {
            $doc = call_user_method('get' . $message->getType(), $message);
            ($message->getType() === 'photo') && $doc = $doc[0];

            $file_id = $doc->getFileId();
            $file = Request::getFile(['file_id' => $file_id]);
            if ($file->isOk() && Request::downloadFile($file->getResult())) {
                $data['text'] = $message->getType() . ' file is located at: ' . $this->telegram->getDownloadPath() . '/' . $file->getResult()->getFilePath();
            } else {
                $data['text'] = 'Failed to download.';
            }

            $this->conversation->notes['file_id'] = $file_id;
            $this->conversation->update();
            $this->conversation->stop();
        } else {
            $data['text'] = 'Please upload the file now';
        }

        return Request::sendMessage($data);
    }
}
progS1m commented 8 years ago

Thanks a lot @noplanman works fine. Except that it will store only the smallest photo version.

noplanman commented 8 years ago

Right, my bad, sorry. The line in question is this one:

($message->getType() === 'Photo') && $doc = $doc[0];

Replace it with this one for the highest resolution:

($message->getType() === 'Photo') && $doc = end($doc);
progS1m commented 8 years ago

Just amazing! Thank you, in my view we can close the issue.

noplanman commented 8 years ago

Ok 👍

We'll be working on a better implementation of this, but until then you can use the /upload command as a workaround.

MostafaSh commented 7 years ago

hi guys! thank you noplanman for answering this issue! but i got some error on your code. I've tried to fix it but I was not successful! these are what I got in error log: [21-Dec-2016 20:46:52 UTC] PHP Deprecated: Function call_user_method() is deprecated in /home/mybotpro/public_html/Project/vendor/longman/telegram-bot/src/Commands/UserCommands/SendImgCommand.php on line 82 [21-Dec-2016 20:46:52 UTC] PHP Fatal error: Call to a member function getFileId() on array in /home/mybotpro/public_html/Project/vendor/longman/telegram-bot/src/Commands/UserCommands/SendImgCommand.php on line 85

what can I do to fix this?

noplanman commented 7 years ago

Could you post the code of your SendImgCommand.php please?

MostafaSh commented 7 years ago
<?php
/**
 * This file is part of the TelegramBot package.
 *
 * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Longman\TelegramBot\Commands\UserCommands;

use Longman\TelegramBot\Request;
use Longman\TelegramBot\Conversation;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\ForceReply;
use Longman\TelegramBot\Entities\ReplyKeyboardHide;
use Longman\TelegramBot\TelegramLog;
/**
 * User "/cancel" command
 *
 * This command cancels the currently active conversation and
 * returns a message to let the user know which conversation it was.
 * If no conversation is active, the returned message says so.
 */
class SendImgCommand extends UserCommand
{
    /**
     * @var string
     */
    protected $name = 'sendimg';

    /**
     * @var string
     */
    protected $description = 'ارسال عکس';

    /**
     * @var string
     */
    protected $usage = '/sendimg';

    /**
     * @var string
     */
    protected $version = '0.2.0';

    protected $conversation;

    /**
     * {@inheritdoc}
     */
    public function execute()
    {
        $servername = "mybotprovider.ir";
        $username = "mybotpro_admin";
        $password = "1a2a3a4197";
        $dbname = "mybotpro_telegram";

        $mysql_credentials = [
        'host'     => $servername,
        'user'     => $username,
        'password' => $password,
        'database' => $dbname,
        ];

    $this->telegram->enableMySQL($mysql_credentials);

        $message = $this->getMessage();
        $chat_id  = $message->getChat()->getId();
        $from       = $message->getFrom();
        $user_name    = $from->getUsername();
        $user_id    = $from->getId();

        //Preparing Response
        $data = [
            'chat_id'      => $chat_id,
        ];

            $doc = call_user_method('get' . $message->getType(), $message);
            ($message->getType() === 'Photo') && $doc = $doc[0];

            $file_id = $doc->getFileId();
            $file = Request::getFile(['file_id' => $file_id]);
            if ($file->isOk() && Request::downloadFile($file->getResult())) {
                $data['text'] = $message->getType() . ' file is located at: ' . $this->telegram->getDownloadPath() . '/' . $file->getResult()->getFilePath();
            } else {
                $data['text'] = 'Failed to download.';
            }

        return Request::sendMessage($data);
    }
}
MostafaSh commented 7 years ago

also i got this error when i was trying to connect to mysql for creating a conversation.

[21-Dec-2016 20:36:52 UTC] PHP Warning: date(): It is not safe to rely on the system's timezone settings. You are required to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /home/mybotpro/public_html/Project/vendor/longman/telegram-bot/src/DB.php on line 245 [21-Dec-2016 20:36:52 UTC] PHP Warning: PDOStatement::execute(): SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (mybotpro_telegram.conversation, CONSTRAINT conversation_ibfk_1 FOREIGN KEY (user_id) REFERENCES user (id)) in /home/mybotpro/public_html/Project/vendor/longman/telegram-bot/src/ConversationDB.php on line 107

MostafaSh commented 7 years ago

I got the second error in this code:

<?php
/**
 * This file is part of the TelegramBot package.
 *
 * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Longman\TelegramBot\Commands\UserCommands;

use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Conversation;
use Longman\TelegramBot\Entities\Keyboard;
use Longman\TelegramBot\Request;
use Longman\TelegramBot\Telegram;
/**
 * User "/cancel" command
 *
 * This command cancels the currently active conversation and
 * returns a message to let the user know which conversation it was.
 * If no conversation is active, the returned message says so.
 */
class SendImgCommand extends UserCommand
{
    /**
     * @var string
     */
    protected $name = 'sendimg';

    /**
     * @var string
     */
    protected $description = 'ارسال عکس';

    /**
     * @var string
     */
    protected $usage = '/sendimg';

    /**
     * @var string
     */
    protected $version = '0.2.0';

    protected $conversation;

    /**
     * {@inheritdoc}
     */
    public function execute()
    {
        $servername = "mybotprovider.ir";
        $username = "mybotpro_admin";
        $password = "1a2a3a4197";
        $dbname = "mybotpro_telegram";

        $mysql_credentials = [
        'host'     => $servername,
        'user'     => $username,
        'password' => $password,
        'database' => $dbname,
        ];

        $telegram->enableMySQL($mysql_credentials);

        $message = $this->getMessage();

        $chat = $message->getChat();
        $user = $message->getFrom();

        $chat_id = $chat->getId();
        $user_id = $user->getId();

        //Preparing Response
        $data = [
            'chat_id'      => $chat_id,
        ];

        //Conversation start
        $this->conversation = new Conversation($user_id, $chat_id, $this->getName());

        if (in_array($message->getType(), ['Audio', 'Document', 'Photo', 'Video', 'Voice'])) {
            $doc = call_user_method('get' . $message->getType(), $message);
            ($message->getType() === 'Photo') && $doc = $doc[0];

            $file_id = $doc->getFileId();
            $file = Request::getFile(['file_id' => $file_id]);
            if ($file->isOk() && Request::downloadFile($file->getResult())) {
                $data['text'] = $message->getType() . ' file is located at: ' . $this->telegram->getDownloadPath() . '/' . $file->getResult()->getFilePath();
            } else {
                $data['text'] = 'Failed to download.';
            }

            $this->conversation->notes['file_id'] = $file_id;
            $this->conversation->update();
            $this->conversation->stop();
        } else {
            $data['text'] = 'Please upload the file now';
        }

        return Request::sendMessage($data);
    }
}
MostafaSh commented 7 years ago

hey noplanman! thanks a lot for your response.

I'm waiting for your answer. as you know, there aren't many sources about creating telegram bot on php. so I'm really looking forward to hearing an answer from you.

my main problems are:

I'm waiting ... so please don't let me down.

noplanman commented 7 years ago

First of all, the MySQL connection info shouldn't be here, it should be in your hook.php.

Also, the getType method returns a lowercase string since version 0.36 (I think). Some lines need to be changed, namely:

...
if (in_array($message->getType(), ['audio', 'document', 'photo', 'video', 'voice'], true)) {
    $doc = call_user_func([$message, 'get' . ucfirst($message->getType())]);
    ($message->getType() === 'photo') && $doc = $doc[0];
...

Does that help enough?

MostafaSh commented 7 years ago

thank you so mush noplanman! you actually have saved my life !!! now i can get filepath without any problem.

but about mysql connection i also have some problems. I set mysql connection method inside hook.php and then unset webhook and reset it. but when i put this line: protected $need_mysql = true; inside SendImgCommand.php and run it, I get this message in my bot: Sorry no database connection, unable to execute "sendimg" command.

this is my hook.php:

<?php
// Load composer
require __DIR__ . '/vendor/autoload.php';

$API_KEY = 'api-key';
$BOT_NAME = 'bot-name';
try {
    // Create Telegram API object
    $telegram = new Longman\TelegramBot\Telegram($API_KEY, $BOT_NAME);

    // Handle telegram webhook request
    $telegram->handle();

    $mysql_credentials = [
   'host'     => 'mybotprovider.ir',
   'user'     => 'mybotpro_admin',
   'password' => '1a2a3a4197',
   'database' => 'mybotpro_telegram',
    ];

    $telegram->enableMySQL($mysql_credentials);

} catch (Longman\TelegramBot\Exception\TelegramException $e) {
    // Silence is golden!
    // log telegram errors
    // echo $e;
}

?>

So what do you think about it? what is the problem?

noplanman commented 7 years ago

You need to enable MySQL before handling the request! 😉

(on a side note, when you post code, use the triple backticks with PHP syntax highlighting. Edit your comment above to see what I mean and read more about it here)

MostafaSh commented 7 years ago

thank you so much noplanman!

you did the best for me, but I can't do anything for you except being Grateful and have best wishes for you! thanks you a lot!

noplanman commented 7 years ago

You're so welcome 😊 Happy to hear it's working now.