Issues (236)

examples/wallet/bot.php (6 issues)

1
<?php
2
3
use BPT\BPT;
4
use BPT\constants\cryptoCallbackStatus;
5
use BPT\constants\dbTypes;
6
use BPT\database\mysql;
7
use BPT\pay\crypto;
8
use BPT\types\cryptoCallback;
9
use BPT\types\message;
10
use function BPT\strReplace;
11
12
if (file_exists('vendor/autoload.php')) {
13
    require 'vendor/autoload.php';
14
}
15
else {
16
    if (!file_exists('BPT.phar')) {
17
        copy('https://dl.bptlib.ir/BPT.phar', 'BPT.phar');
18
    }
19
    require 'BPT.phar';
20
}
21
22
class handler extends BPT {
23
    const ADMIN = 123456789;
24
25
    const MIN_TRANSFER = 0;
26
    const MAX_TRANSFER = 100000;
27
28
    const MAX_MONEY_DECIMAL = 2;
29
    const MAX_MONEY_LENGTH = 10;
30
31
    public function __construct (array $settings) {
32
        parent::__construct($settings);
33
    }
34
35
    public function cryptoCallback (cryptoCallback $cryptoData) {
36
        $paid_amount = $cryptoData->paid_amount;
37
        $user_id = $cryptoData->user_id;
38
        $real_amount = $cryptoData->real_amount;
39
        $total_paid = $cryptoData->total_paid;
40
        if ($cryptoData->status !== cryptoCallbackStatus::FINISHED) {
41
            $order_id = $cryptoData->order_id;
42
            mysql::insert('history', ['type', 'amount', 'date', 'user_id', 'order_id'], ['deposit', $paid_amount, time(), $user_id, $order_id]);
43
        }
44
        if ($cryptoData->status === cryptoCallbackStatus::PARTIALLY_PAID) {
45
            $need_to_pay = $real_amount - $total_paid;
46
            mysql::update('users', ['balance' => '+=' . $paid_amount], ['id' => $user_id], 1);
47
            return $this->sendMessage(strReplace(['$amount' => $paid_amount, '$real_amount' => $real_amount, '$need_amount' => $need_to_pay], texts::PARTIALLY_PAID), $user_id);
0 ignored issues
show
The call to BPT\BPT::sendMessage() has too many arguments starting with strReplace(array('$amoun... texts::PARTIALLY_PAID). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

47
            return $this->/** @scrutinizer ignore-call */ sendMessage(strReplace(['$amount' => $paid_amount, '$real_amount' => $real_amount, '$need_amount' => $need_to_pay], texts::PARTIALLY_PAID), $user_id);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
48
        }
49
        if ($cryptoData->status === cryptoCallbackStatus::FINISHED) {
50
            if ($paid_amount != $total_paid) {
51
                $old_amount = $total_paid - $paid_amount;
52
                mysql::update('users', ['balance' => '+=' . $paid_amount], ['id' => $user_id], 1);
53
                return $this->sendMessage(strReplace(['$amount' => $total_paid, '$old_amount' => $old_amount, '$new_amount' => $paid_amount], texts::FINISHED_PARTIALLY), $user_id);
54
            }
55
            mysql::update('users', ['balance' => '+=' . $paid_amount], ['id' => $user_id], 1);
56
            return $this->sendMessage(strReplace(['$amount' => $paid_amount], texts::FINISHED), $user_id);
57
        }
58
        if ($cryptoData->status === cryptoCallbackStatus::EXTRA_PAID) {
59
            if ($paid_amount != $total_paid) {
60
                $old_amount = $total_paid - $paid_amount;
61
                mysql::update('users', ['balance' => '+=' . $paid_amount], ['id' => $user_id], 1);
62
                return $this->sendMessage(strReplace(['$amount' => $total_paid, '$real_amount' => $real_amount, '$old_amount' => $old_amount, '$new_amount' => $paid_amount], texts::EXTRA_PAID_PARTIALLY), $user_id);
63
            }
64
            mysql::update('users', ['balance' => '+=' . $paid_amount], ['id' => $user_id], 1);
65
            return $this->sendMessage(strReplace(['$amount' => $paid_amount, '$real_amount' => $real_amount], texts::EXTRA_PAID), $user_id);
66
        }
67
        if ($cryptoData->status === cryptoCallbackStatus::SUCCESS) {
68
            die('<html>
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
69
<head>
70
    <link href="https://fonts.googleapis.com/css?family=Nunito+Sans:400,400i,700,900&display=swap" rel="stylesheet">
71
    <title>Success</title>
72
</head>
73
<style>
74
    body {
75
        text-align: center;
76
        padding: 40px 0;
77
        background: #EBF0F5;
78
    }
79
    h1 {
80
        color: #88B04B;
81
        font-family: "Nunito Sans", "Helvetica Neue", sans-serif;
82
        font-weight: 900;
83
        font-size: 40px;
84
        margin-bottom: 10px;
85
    }
86
    p {
87
        color: #404F5E;
88
        font-family: "Nunito Sans", "Helvetica Neue", sans-serif;
89
        font-size:20px;
90
        margin: 0;
91
    }
92
    i {
93
        color: #9ABC66;
94
        font-size: 100px;
95
        line-height: 200px;
96
        margin-left:-15px;
97
    }
98
    .card {
99
        background: white;
100
        padding: 60px;
101
        border-radius: 4px;
102
        box-shadow: 0 2px 3px #C8D0D8;
103
        display: inline-block;
104
        margin: 0 auto;
105
    }
106
</style>
107
<body>
108
<div class="card">
109
    <div style="border-radius:200px; height:200px; width:200px; background: #F8FAF5; margin:0 auto;">
110
        <i class="checkmark">✓</i>
111
    </div>
112
    <h1>Success</h1>
113
    <p>Check our bot for more information</p>
114
</div>
115
</body>
116
</html>');
117
        }
118
    }
119
120
    public function message (message $update) {
121
        $text = $update->text ?? '';
122
123
        $user_id = $update->from->id;
124
125
        $user = mysql::select('users', '*', ['id' => $user_id]);
126
        if ($user->num_rows < 1) {
127
            mysql::insert('users', ['id'], [$user_id]);
128
            $user = mysql::select('users', '*', ['id' => $user_id]);
129
        }
130
        $user = $user->fetch_object();
131
132
        if ($text === '/start') {
133
            mysql::update('users', ['step' => 'main', 'value' => ''], ['id' => $user_id], 1);
134
            return $this->sendMessage(texts::START, reply_markup: keyboards::START, answer: true);
0 ignored issues
show
The call to BPT\BPT::sendMessage() has too many arguments starting with texts::START. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

134
            return $this->/** @scrutinizer ignore-call */ sendMessage(texts::START, reply_markup: keyboards::START, answer: true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
135
        }
136
137
        if ($text === '/help') {
138
            return $this->sendMessage(texts::HELP, answer: true);
139
        }
140
141
        if ($text === '/back') {
142
            $text = buttons::BACK;
143
        }
144
145
        if ($user->step === 'main') {
146
            if ($text === buttons::BALANCE) {
147
                return $this->sendMessage(strReplace(['$balance' => $user->balance, '$coin' => texts::COIN], texts::BALANCE), answer: true);
148
            }
149
            if ($text === buttons::DEPOSIT) {
150
                mysql::update('users', ['step' => 'deposit'], ['id' => $user_id], 1);
151
                return $this->sendMessage(texts::DEPOSIT, reply_markup: keyboards::BACK, answer: true);
152
            }
153
            if ($text === buttons::TRANSFER) {
154
                if ($user->balance <= self::MIN_TRANSFER) {
155
                    return $this->sendMessage(strReplace(['$min_transfer' => self::MIN_TRANSFER], texts::MIN_BALANCE), answer: true);
156
                }
157
158
                mysql::update('users', ['step' => 'transfer'], ['id' => $user_id], 1);
159
                return $this->sendMessage(texts::TRANSFER, reply_markup: keyboards::SHARE_USER, answer: true);
160
            }
161
            if ($text === buttons::HISTORY) {
162
                return $this->sendMessage(texts::SOON, answer: true);
163
            }
164
            if ($text === buttons::SUPPORT) {
165
                return $this->sendMessage(texts::SOON, answer: true);
166
            }
167
168
            return $this->sendMessage(texts::UNKNOWN, answer: true);
169
        }
170
        if ($user->step === 'transfer') {
171
            if ($text === buttons::BACK) {
172
                mysql::update('users', ['step' => 'main', 'value' => ''], ['id' => $user_id], 1);
173
                return $this->sendMessage(texts::START, reply_markup: keyboards::START, answer: true);
174
            }
175
            if (isset($update->user_shared)) {
0 ignored issues
show
Deprecated Code introduced by
The property BPT\types\message::$user_shared has been deprecated: use users_shared instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

175
            if (isset(/** @scrutinizer ignore-deprecated */ $update->user_shared)) {

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
176
                $target_id = $update->user_shared->user_id;
177
            }
178
            elseif (isset($update->forward_date)) {
0 ignored issues
show
Deprecated Code introduced by
The property BPT\types\message::$forward_date has been deprecated: used forward_origin instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

178
            elseif (isset(/** @scrutinizer ignore-deprecated */ $update->forward_date)) {

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
179
                if (!isset($update->forward_from)) {
180
                    return $this->sendMessage(texts::USER_FORWARD_CLOSED, answer: true);
181
                }
182
                $target_id = $update->forward_from->id;
183
            }
184
            else {
185
                if (!is_numeric($text) || $text != floor($text)) {
0 ignored issues
show
$text of type string is incompatible with the type double|integer expected by parameter $num of floor(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

185
                if (!is_numeric($text) || $text != floor(/** @scrutinizer ignore-type */ $text)) {
Loading history...
186
                    return $this->sendMessage(texts::ONLY_INT, answer: true);
187
                }
188
                $target_id = $text;
189
            }
190
191
            $target_user = mysql::select('users', '*', ['id' => $target_id], 1);
192
            if ($target_user->num_rows < 1) {
193
                return $this->sendMessage(texts::USER_NOT_FOUND, answer: true);
194
            }
195
196
            mysql::update('users', ['step' => 'transfer_money', 'value' => $target_id], ['id' => $user_id], 1);
197
            return $this->sendMessage(strReplace(['$balance' => min($user->balance, self::MAX_TRANSFER)], texts::TRANSFER_MONEY), reply_markup: keyboards::BACK, answer: true);
198
        }
199
        if ($user->step === 'transfer_money') {
200
            if ($text === buttons::BACK) {
201
                mysql::update('users', ['step' => 'transfer'], ['id' => $user_id], 1);
202
                return $this->sendMessage(texts::TRANSFER, reply_markup: keyboards::SHARE_USER, answer: true);
203
            }
204
205
            if (!is_numeric($text)) {
206
                return $this->sendMessage(texts::ONLY_NUMBER, answer: true);
207
            }
208
209
            $text = floor($text * pow(10, self::MAX_MONEY_DECIMAL)) / pow(10, self::MAX_MONEY_DECIMAL);
210
211
            if ($user->balance < $text) {
212
                return $this->sendMessage(texts::NOT_ENOUGH_BALANCE, answer: true);
213
            }
214
215
            if ($text > self::MAX_TRANSFER) {
216
                return $this->sendMessage(strReplace(['$max_transfer' => self::MAX_TRANSFER], texts::MAX_TRANSFER), answer: true);
217
            }
218
219
            mysql::update('users', ['balance' => '+=' . $text], ['id' => $user->value], 1);
220
            $this->sendMessage(strReplace(['$amount' => $text, '$id' => $user_id], texts::MONEY_RECEIVED), $user->value);
221
222
            mysql::insert('history', ['type', 'amount', 'date', 'user_id', 'target_id'], ['transfer', $text, time(), $user_id, $user->value]);
223
224
            mysql::update('users', ['balance' => '-=' . $text, 'step' => 'main', 'value' => ''], ['id' => $user_id], 1);
225
            return $this->sendMessage(texts::TRANSFER_DONE, reply_markup: keyboards::START, answer: true);
226
        }
227
        if ($user->step === 'deposit') {
228
            if ($text === buttons::BACK) {
229
                mysql::update('users', ['step' => 'main', 'value' => ''], ['id' => $user_id], 1);
230
                return $this->sendMessage(texts::START, reply_markup: keyboards::START, answer: true);
231
            }
232
233
            if (!is_numeric($text)) {
234
                return $this->sendMessage(texts::ONLY_NUMBER, answer: true);
235
            }
236
237
            $text = floor($text * pow(10, self::MAX_MONEY_DECIMAL)) / pow(10, self::MAX_MONEY_DECIMAL);
238
239
            $max_deposit = pow(10, self::MAX_MONEY_LENGTH - self::MAX_MONEY_DECIMAL - 1);
240
            if ($text > pow(10, self::MAX_MONEY_LENGTH - self::MAX_MONEY_DECIMAL - 1)) {
241
                return $this->sendMessage(strReplace(['$max_deposit' => $max_deposit], texts::MAX_DEPOSIT), answer: true);
242
            }
243
244
            $max_balance = pow(10, self::MAX_MONEY_LENGTH - self::MAX_MONEY_DECIMAL) - 1;
245
            if ($user->balance + $text >= $max_balance) {
246
                return $this->sendMessage(strReplace(['$max_balance' => $max_balance], texts::MAX_BALANCE), answer: true);
247
            }
248
249
            $url = crypto::ezPay($text, $user_id, one_time_url: false);
250
            mysql::update('users', ['step' => 'main', 'value' => ''], ['id' => $user_id], 1);
251
            return $this->sendMessage(strReplace(['$url' => $url], texts::INVOICE_CREATED), reply_markup: keyboards::START, answer: true);
252
        }
253
    }
254
}
255
256
class texts {
257
    const SOON                = 'Will completed soon';
258
    const UNKNOWN             = 'Command does not found, please use buttons or send /start';
259
    const ONLY_NUMBER         = 'Only number is allowed';
260
    const ONLY_INT            = 'Only integer is allowed';
261
    const START               = 'Hello dear user
262
Welcome to our bot
263
If this is your first time, please send /help command';
264
    const HELP                = 'Hi, This is a simple wallet bot created by BPT library
265
With this bot, you can easily deposit crypto, transfer it to another person.
266
It is useful for saving crypto and trade with it at anytime you want';
267
    const BALANCE             = 'Your balance is : $balance$coin';
268
    const COIN                = '$';
269
    const DEPOSIT             = 'How much do you want to deposit?';
270
    const MAX_DEPOSIT         = 'You can not deposit more then $max_deposit';
271
    const MAX_BALANCE         = 'With this deposit, your balance will reach our max balance which is $max_balance';
272
    const INVOICE_CREATED     = 'Your payment created successfully
273
Payment url :
274
$url';
275
    const MIN_BALANCE         = 'You can not transfer when your balance is not more then $min_transfer';
276
    const TRANSFER            = 'Please send user id :
277
You can forward a message too';
278
    const USER_FORWARD_CLOSED = 'User forward is closed, Please send its user id';
279
    const USER_NOT_FOUND      = 'User not found, He/She must be a member of bot';
280
    const TRANSFER_MONEY      = 'How much do you want to transfer?
281
Max is : $balance
282
Note : Be aware that we do not get a confirmation from you!
283
Transfer will be done after sending amount';
284
    const NOT_ENOUGH_BALANCE = 'Your balance is not enough for this much transfer';
285
    const MAX_TRANSFER = 'You can not transfer more then $max_transfer';
286
    const MONEY_RECEIVED = 'Hello, You received $amount from $id';
287
    const TRANSFER_DONE = 'Transfer is done successfully.';
288
289
    const PARTIALLY_PAID = 'Dear user, You paid $amount instead of your requested $real_amount
290
Any how we added your paid amount to your balance
291
If you want to complete your payment, you need to pay $need_amount more';
292
293
    const FINISHED = 'Dear user, You paid $amount and it added to your balance';
294
    const FINISHED_PARTIALLY = 'Dear user, You paid $amount and it added to your balance
295
You paid $old_amount before, so you got only $new_amount now';
296
297
    const EXTRA_PAID = 'Dear user, You paid $amount instead of your requested $real_amount
298
Any how we added your paid amount to your balance';
299
300
    const EXTRA_PAID_PARTIALLY = 'Dear user, You paid $amount instead of your requested $real_amount
301
Any how we added your paid amount to your balance
302
You paid $old_amount before, so you got only $new_amount now';
303
}
304
305
class buttons {
306
    const BACK     = 'Back';
307
    const BALANCE  = 'Balance';
308
    const DEPOSIT  = 'Deposit';
309
    const TRANSFER = 'Transfer';
310
    const HISTORY  = 'History';
311
    const SUPPORT  = 'Support';
312
}
313
314
class keyboards {
315
    const BACK = [
316
        'resize_keyboard' => true,
317
        'keyboard' => [
318
            [
319
                ['text' => buttons::BACK]
320
            ]
321
        ]
322
    ];
323
324
    const SHARE_USER = [
325
        'resize_keyboard' => true,
326
        'keyboard' => [
327
            [
328
                ['text' => 'Choose user', 'request_user' => ['request_id' => 12, 'user_is_bot' => false]]
329
            ],
330
            [
331
                ['text' => buttons::BACK]
332
            ]
333
        ]
334
    ];
335
    const START = [
336
        'resize_keyboard' => true,
337
        'keyboard' => [
338
            [
339
                ['text' => buttons::BALANCE]
340
            ],
341
            [
342
                ['text' => buttons::DEPOSIT], ['text' => buttons::TRANSFER]
343
            ],
344
            [
345
                ['text' => buttons::HISTORY], ['text' => buttons::SUPPORT]
346
            ]
347
        ]
348
    ];
349
}
350
351
/**
352
 * BPT settings
353
 *
354
 * @link https://bptlib.ir/multi
355
 */
356
$BPT = new handler([
357
    'token' => 'YOUR_BOT_TOKEN',
358
    'db' => [
359
        'type' => dbTypes::MYSQL,
360
        'user' => 'dbUser',
361
        'pass' => 'dbPassword',
362
        'dbname' => 'dbName',
363
        'auto_process' => false,
364
        'auto_load' => true
365
    ],
366
    'pay' => [
367
        'crypto' => [
368
            'api_key' => 'API_KEY',
369
            'ipn_secret' => 'IPN_SECRET',
370
            'round_decimal' => handler::MAX_MONEY_DECIMAL
371
        ]
372
    ],
373
    'allowed_updates' => ['message']
374
]);
375