├── LICENSE ├── README.md └── src ├── Autoloader.php ├── Bot.php ├── Chat.php ├── Elements ├── Audio.php ├── Base.php ├── ChatMember.php ├── Document.php ├── Location.php ├── MessageEntity.php ├── PhotoSize.php ├── Sticker.php ├── Venue.php ├── Video.php ├── VideoNote.php └── Voice.php ├── Emojis.php ├── Keyboards ├── InlineKeyboard.php └── Keyboard.php ├── Message.php ├── Payments └── Stripe.php ├── Receiver.php ├── Sender.php ├── Sticker.php └── User.php /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Telegram-PHP 2 | 3 | Another library to use Telegram bots with PHP. 4 | 5 | - Include the **src/Autoloader.php** file. 6 | - Create a *Telegram\Bot* object. 7 | - Create a *Telegram\Receiver* object using the *$bot*. 8 | 9 | ```php 10 | $bot = new Telegram\Bot("11111111:AAAAAAAAAAzzzzzzzzzzzzzzzzzzz", "MyUserBot", "The Name of Bot"); 11 | $tg = new Telegram\Receiver($bot); 12 | ``` 13 | 14 | You can create as many *Bots* and *Receivers* or *Senders* as you want. 15 | Using *Receiver* includes a *Sender*. 16 | 17 | # Usage 18 | 19 | Once the page is loaded (manually or via webhook), you can send or reply the requests. 20 | 21 | To send a message to a user or group chat: 22 | ```php 23 | $tg->send 24 | ->chat("123456") 25 | ->text("Hello world!") 26 | ->send(); 27 | ``` 28 | 29 | To reply a user command: 30 | ```php 31 | if($tg->text_command("start")){ 32 | $tg->send 33 | ->text("Hi!") 34 | ->send(); 35 | } 36 | ``` 37 | 38 | To reply a user message: 39 | ```php 40 | if($tg->text_has("are you alive")){ 41 | $tg->send 42 | ->text("Yes!") 43 | ->send(); 44 | } 45 | ``` 46 | 47 | **NEW:** To parse a string: 48 | ```php 49 | if($tg->text_regex("I'm {N:age}") and $tg->words() <= 4){ 50 | $num = $tg->input->age; 51 | $str = "So old..."; 52 | if($num < 18){ $str = "You're young!"; } 53 | $tg->send 54 | ->text($str) 55 | ->send(); 56 | }elseif($tg->text_regex("My name's {name}")){ 57 | $tg->send 58 | ->text("Nice to meet you, " .$tg->input->name ."!") 59 | ->send(); 60 | } 61 | ``` 62 | 63 | Send an Inline Keyboard and parse it: 64 | ```php 65 | if($tg->callback == "but 1"){ 66 | $tg->answer_if_callback(""); // Stop loading button. 67 | $tg->send 68 | ->message(TRUE) 69 | ->chat(TRUE) 70 | ->text("You pressed the first button!") 71 | ->edit("text"); 72 | }elseif($tg->callback == "but 2"){ 73 | $tg->answer_if_callback("You pressed the second button!", TRUE); 74 | // Display an alert and stop loading button. 75 | } 76 | 77 | if($tg->text_has("matrix") and $tg->words() <= 5){ 78 | $tg->send 79 | ->text("Red or blue. You choose.") 80 | ->inline_keyboard() 81 | ->row() 82 | ->button("Red", "but 1") 83 | ->button("Blue", "but 2") 84 | ->end_row() 85 | ->show() 86 | ->send(); 87 | } 88 | ``` 89 | 90 | # Examples 91 | - [Profesor Oak](https://github.com/duhow/ProfesorOak), an assistant for Pokemon GO. 92 | -------------------------------------------------------------------------------- /src/Autoloader.php: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /src/Bot.php: -------------------------------------------------------------------------------- 1 | 2){ 19 | foreach($id as $k => $v){ $$k = $v; } 20 | }elseif(is_string($id) && strpos($id, ":") !== FALSE){ 21 | $id = explode(":", $id); 22 | if(empty($first_name) && !empty($username) && !empty($key)){ 23 | $first_name = $username; 24 | $username = $key; 25 | }elseif(empty($username) && !empty($key)){ 26 | $username = $key; 27 | } 28 | $key = $id[1]; 29 | $id = $id[0]; 30 | } 31 | 32 | $this->key = trim($key); 33 | return parent::__construct($id, $first_name, NULL, $username, NULL, TRUE); 34 | } 35 | 36 | /* public function info(){ 37 | $send = new Sender($this); 38 | // TODO getWebhookInfo and return array with data 39 | } */ 40 | 41 | public function __toString(){ 42 | return ("@" .$this->username); 43 | } 44 | } 45 | 46 | ?> 47 | -------------------------------------------------------------------------------- /src/Chat.php: -------------------------------------------------------------------------------- 1 | type == "private"){ return FALSE; } 15 | if($this->type == "channel" and !$or_channel){ return FALSE; } 16 | return TRUE; // group / supergroup 17 | } 18 | 19 | public function parse($bot, $full = FALSE){ 20 | if(is_bool($bot)){ 21 | // Flip if needed 22 | $tmp = $bot; 23 | $bot = $full; 24 | $full = $tmp; 25 | unset($tmp); 26 | } 27 | $this->info($bot); 28 | if($full == TRUE){ 29 | $this->admins($bot); 30 | $this->count($bot); 31 | } 32 | } 33 | 34 | public function admins($bot = NULL){ 35 | if(!empty($this->admins) or empty($bot)){ return $this->admins; } 36 | $send = new Sender($bot); 37 | $admins = $send->get_admins($this->id); 38 | foreach($admins as $u){ 39 | $this->admins[] = $u['user']['id']; 40 | if($u['status'] == 'creator'){ 41 | $this->creator = $u['user']['id']; 42 | } 43 | } 44 | return $this->admins; 45 | } 46 | 47 | public function count($bot = NULL){ 48 | if(!empty($this->members) or empty($bot)){ return $this->members; } 49 | $send = new Sender($bot); 50 | $this->members = $send->get_members_count($this->id); 51 | return $this->members; 52 | } 53 | 54 | public function ban($user, $bot){ return $this->__admin_user_kick($user, $bot, 'ban'); } 55 | public function kick($user, $bot){ return $this->__admin_user_kick($user, $bot, 'kick'); } 56 | public function unban($user, $bot){ return $this->__admin_user_kick($user, $bot, 'unban'); } 57 | private function __admin_user_kick($user, $bot, $action){ 58 | // Flip if needed 59 | if($user instanceof Bot){ 60 | $tmp = $bot; 61 | $bot = $user; 62 | $user = $tmp; 63 | unset($tmp); 64 | } 65 | if($user instanceof User){ $user = $user->id; } 66 | $send = new Sender($bot); 67 | return $send->$action($user, $this->id); 68 | } 69 | 70 | // TODO Cleanup code 71 | public function link($bot = NULL, $html = FALSE){ 72 | $url = NULL; 73 | if(isset($this->username) and !empty($this->username)){ 74 | $url = "https://t.me/" .$this->username; 75 | }elseif(isset($this->invite_link) and !empty($this->invite_link)){ 76 | $url = $this->invite_link; 77 | } 78 | if(!$html and $url){ return $url; } 79 | elseif($html and $url){ return '' . $html .''; } 80 | 81 | $send = new Sender($bot); 82 | return $send->get_chat_link($this->id); 83 | } 84 | 85 | public function __construct($id, $type = NULL){ 86 | unset($this->is_bot); 87 | 88 | if(is_array($id)){ 89 | foreach($id as $k => $v){ $this->$k = $v; } 90 | }else{ 91 | $this->id = intval($id); 92 | $this->type = $type; 93 | } 94 | 95 | foreach(['first_name', 'last_name', 'title'] as $name){ 96 | if(!empty($this->{$name})){ 97 | $this->{$name} = str_replace("\u{202e}", "", $this->{$name}); 98 | } 99 | } 100 | 101 | if($this->type == "private"){ 102 | $this->members = 2; 103 | unset($this->all_members_are_administrators); 104 | unset($this->title); 105 | }else{ 106 | unset($this->first_name); 107 | unset($this->last_name); 108 | } 109 | return $this; 110 | } 111 | 112 | public function __toString(){ 113 | if($this->type != "private"){ return $this->title; } // Group or channel 114 | return trim($this->first_name ." " .$this->last_name); // User 115 | } 116 | } 117 | 118 | ?> 119 | -------------------------------------------------------------------------------- /src/Elements/Audio.php: -------------------------------------------------------------------------------- 1 | file_id; 15 | } 16 | } 17 | 18 | ?> 19 | -------------------------------------------------------------------------------- /src/Elements/Base.php: -------------------------------------------------------------------------------- 1 | $v){ $this->$k = $v; } 12 | } 13 | } 14 | 15 | function __toString(){ 16 | return (string) $this->file_id; 17 | } 18 | } 19 | 20 | ?> 21 | -------------------------------------------------------------------------------- /src/Elements/ChatMember.php: -------------------------------------------------------------------------------- 1 | $v){ 26 | if(strpos($k, "can_") === 0){ 27 | $this->$k = (bool) $v; 28 | }else{ 29 | $this->$k = $v; 30 | } 31 | } 32 | } 33 | } 34 | } 35 | 36 | ?> 37 | -------------------------------------------------------------------------------- /src/Elements/Document.php: -------------------------------------------------------------------------------- 1 | thumb = $photo; 16 | return $this; 17 | } 18 | 19 | function __toString(){ 20 | return (string) $this->file_id; 21 | } 22 | } 23 | 24 | ?> 25 | -------------------------------------------------------------------------------- /src/Elements/Location.php: -------------------------------------------------------------------------------- 1 | $v){ $this->$k = $v; } 12 | }elseif(is_float($data) and is_float($lon)){ 13 | $this->latitude = $data; 14 | $this->longitude = $lon; 15 | }elseif(is_string($data) and strpos($data, ",") !== FALSE){ 16 | $data = explode(",", $data); 17 | if(count($data) == 2){ 18 | $this->latitude = $data[0]; 19 | $this->longitude = $data[1]; 20 | } 21 | } 22 | } 23 | 24 | function __toString(){ 25 | return (string) $this->latitude .", " .$this->longitude; 26 | } 27 | } 28 | 29 | ?> 30 | -------------------------------------------------------------------------------- /src/Elements/MessageEntity.php: -------------------------------------------------------------------------------- 1 | $v){ $this->$k = $v; } 17 | } 18 | if($this->type == "text_mention"){ $this->user = new User($data['user']); } 19 | elseif(!empty($text) && in_array($this->type, ['url', 'text_link', 'bot_command', 'mention', 'hashtag', 'email'])){ 20 | // TODO 21 | if(function_exists('mb_convert_encoding')){ 22 | // $text = mb_convert_encoding($text, 'UTF-16', 'UTF-8'); 23 | } 24 | $this->value = substr($text, $this->offset, $this->length); 25 | } 26 | } 27 | 28 | function __toString(){ 29 | if($this->type == "text_mention"){ return (string) $this->user->id; } 30 | return (string) $this->value; 31 | } 32 | } 33 | 34 | ?> 35 | -------------------------------------------------------------------------------- /src/Elements/PhotoSize.php: -------------------------------------------------------------------------------- 1 | file_id; 15 | } 16 | } 17 | 18 | ?> 19 | -------------------------------------------------------------------------------- /src/Elements/Sticker.php: -------------------------------------------------------------------------------- 1 | thumb = $photo; 17 | return $this; 18 | } 19 | 20 | function __toString(){ 21 | return (string) $this->file_id; 22 | } 23 | } 24 | 25 | ?> 26 | -------------------------------------------------------------------------------- /src/Elements/Venue.php: -------------------------------------------------------------------------------- 1 | $v){ $this->$k = $v; } 14 | } 15 | if(isset($data['latitude']) and isset($data['longitude'])){ 16 | $this->location = new Location($data); 17 | } 18 | } 19 | 20 | function __toString(){ 21 | return (string) $this->title ."\n" .$this->address; 22 | } 23 | } 24 | 25 | ?> 26 | -------------------------------------------------------------------------------- /src/Elements/Video.php: -------------------------------------------------------------------------------- 1 | thumb = $photo; 18 | return $this; 19 | } 20 | 21 | function __toString(){ 22 | return (string) $this->file_id; 23 | } 24 | } 25 | 26 | ?> 27 | -------------------------------------------------------------------------------- /src/Elements/VideoNote.php: -------------------------------------------------------------------------------- 1 | thumb = $photo; 16 | return $this; 17 | } 18 | 19 | function __toString(){ 20 | return (string) $this->file_id; 21 | } 22 | } 23 | 24 | ?> 25 | -------------------------------------------------------------------------------- /src/Elements/Voice.php: -------------------------------------------------------------------------------- 1 | file_id; 15 | } 16 | } 17 | 18 | ?> 19 | -------------------------------------------------------------------------------- /src/Emojis.php: -------------------------------------------------------------------------------- 1 | "\u{1f604}", 3 | ':smiley:' => "\u{1f603}", 4 | ':grinning:' => "\u{1f600}", 5 | ':blush:' => "\u{1f60a}", 6 | ':relaxed:' => "\u{263a}", 7 | ':wink:' => "\u{1f609}", 8 | ':heart_eyes:' => "\u{1f60d}", 9 | ':kissing_heart:' => "\u{1f618}", 10 | ':kissing_closed_eyes:' => "\u{1f61a}", 11 | ':kissing:' => "\u{1f617}", 12 | ':kissing_smiling_eyes:' => "\u{1f619}", 13 | ':stuck_out_tongue_winking_eye:' => "\u{1f61c}", 14 | ':stuck_out_tongue_closed_eyes:' => "\u{1f61d}", 15 | ':stuck_out_tongue:' => "\u{1f61b}", 16 | ':flushed:' => "\u{1f633}", 17 | ':grin:' => "\u{1f601}", 18 | ':pensive:' => "\u{1f614}", 19 | ':relieved:' => "\u{1f60c}", 20 | ':unamused:' => "\u{1f612}", 21 | ':disappointed:' => "\u{1f61e}", 22 | ':persevere:' => "\u{1f623}", 23 | ':cry:' => "\u{1f622}", 24 | ':joy:' => "\u{1f602}", 25 | ':rolling_on_the_floor_laughing:' => "\u{1f923}", 26 | ':sob:' => "\u{1f62d}", 27 | ':sleepy:' => "\u{1f62a}", 28 | ':disappointed_relieved:' => "\u{1f625}", 29 | ':cold_sweat:' => "\u{1f630}", 30 | ':sweat_smile:' => "\u{1f605}", 31 | ':sweat:' => "\u{1f613}", 32 | ':weary:' => "\u{1f629}", 33 | ':tired_face:' => "\u{1f62b}", 34 | ':fearful:' => "\u{1f628}", 35 | ':scream:' => "\u{1f631}", 36 | ':angry:' => "\u{1f620}", 37 | ':rage:' => "\u{1f621}", 38 | ':triumph:' => "\u{1f624}", 39 | ':confounded:' => "\u{1f616}", 40 | ':laughing:' => "\u{1f606}", 41 | ':yum:' => "\u{1f60b}", 42 | ':mask:' => "\u{1f637}", 43 | ':drool:' => "\u{1f924}", 44 | ':sneeze:' => "\u{1f927}", 45 | ':cowboy:' => "\u{1f920}", 46 | ':clown:' => "\u{1f921}", 47 | ':lying_face:' => "\u{1f925}", 48 | ':nerd:' => "\u{1f913}", 49 | ':slightly_smiling_face:' => "\u{1f642}", 50 | ':sunglasses:' => "\u{1f60e}", 51 | ':sleeping:' => "\u{1f634}", 52 | ':dizzy_face:' => "\u{1f635}", 53 | ':astonished:' => "\u{1f632}", 54 | ':worried:' => "\u{1f61f}", 55 | ':frowning:' => "\u{1f626}", 56 | ':anguished:' => "\u{1f627}", 57 | ':smiling_imp:' => "\u{1f608}", 58 | ':imp:' => "\u{1f47f}", 59 | ':open_mouth:' => "\u{1f62e}", 60 | ':grimacing:' => "\u{1f62c}", 61 | ':neutral_face:' => "\u{1f610}", 62 | ':confused:' => "\u{1f615}", 63 | ':hushed:' => "\u{1f62f}", 64 | ':no_mouth:' => "\u{1f636}", 65 | ':innocent:' => "\u{1f607}", 66 | ':smirk:' => "\u{1f60f}", 67 | ':expressionless:' => "\u{1f611}", 68 | ':man_artist:' => "\u{1f468}\u{200d}\u{1f3a8}", 69 | ':man_astronaut:' => "\u{1f468}\u{200d}\u{1f680}", 70 | ':man_biking:' => "\u{1f6b4}", 71 | ':man_bouncing_ball:' => "\u{26f9}\u{fe0f}", 72 | ':man_bowing:' => "\u{1f647}", 73 | ':man_cartwheeling:' => "\u{1f938}\u{200d}\u{2642}\u{fe0f}", 74 | ':man_construction_worker:' => "\u{1f477}", 75 | ':man_cook:' => "\u{1f468}\u{200d}\u{1f373}", 76 | ':man_dancing:' => "\u{1f57a}", 77 | ':man_detective:' => "\u{1f575}\u{fe0f}", 78 | ':man_facepalming:' => "\u{1f926}\u{200d}\u{2642}\u{fe0f}", 79 | ':man_factory_worker:' => "\u{1f468}\u{200d}\u{1f3ed}", 80 | ':man_farmer:' => "\u{1f468}\u{200d}\u{1f33e}", 81 | ':man_fairy:' => "\u{1f9da}\u{200d}\u{2642}\u{fe0f}", 82 | ':man_firefighter:' => "\u{1f468}\u{200d}\u{1f692}", 83 | ':man_frowning:' => "\u{1f64d}\u{200d}\u{2642}\u{fe0f}", 84 | ':man_genie:' => "\u{1f9de}\u{200d}\u{2642}\u{fe0f}", 85 | ':man_gesturing_no:' => "\u{1f645}\u{200d}\u{2642}\u{fe0f}", 86 | ':man_gesturing_ok:' => "\u{1f646}\u{200d}\u{2642}\u{fe0f}", 87 | ':man_getting_face_massage:' => "\u{1f486}\u{200d}\u{2642}\u{fe0f}", 88 | ':man_getting_haircut:' => "\u{1f487}\u{200d}\u{2642}\u{fe0f}", 89 | ':man_golfing:' => "\u{1f3cc}\u{fe0f}", 90 | ':man_guard:' => "\u{1f482}", 91 | ':man_health_worker:' => "\u{1f468}\u{200d}\u{2695}\u{fe0f}", 92 | ':man_in_business_suit_levitating:' => "\u{1f574}", 93 | ':man_in_tuxedo:' => "\u{1f935}", 94 | ':man_judge:' => "\u{1f468}\u{200d}\u{2696}\u{fe0f}", 95 | ':man_juggling:' => "\u{1f939}\u{200d}\u{2642}\u{fe0f}", 96 | ':man_lifting_weights:' => "\u{1f3cb}\u{fe0f}", 97 | ':man_mage:' => "\u{1f9d9}\u{200d}\u{2642}\u{fe0f}", 98 | ':man_mechanic:' => "\u{1f468}\u{200d}\u{1f527}", 99 | ':man_mountain_biking:' => "\u{1f6b5}", 100 | ':man_office_worker:' => "\u{1f468}\u{200d}\u{1f4bc}", 101 | ':man_pilot:' => "\u{1f468}\u{200d}\u{2708}\u{fe0f}", 102 | ':man_playing_handball:' => "\u{1f93e}\u{200d}\u{2642}\u{fe0f}", 103 | ':man_police_officer:' => "\u{1f46e}", 104 | ':man_pouting:' => "\u{1f64e}\u{200d}\u{2642}\u{fe0f}", 105 | ':man_raising_hand:' => "\u{1f64b}\u{200d}\u{2642}\u{fe0f}", 106 | ':man_rowing_boat:' => "\u{1f6a3}", 107 | ':man_running:' => "\u{1f3c3}", 108 | ':man_scientist:' => "\u{1f468}\u{200d}\u{1f52c}", 109 | ':man_shrugging:' => "\u{1f937}\u{200d}\u{2642}\u{fe0f}", 110 | ':man_singer:' => "\u{1f468}\u{200d}\u{1f3a4}", 111 | ':man_student:' => "\u{1f468}\u{200d}\u{1f393}", 112 | ':man_teacher:' => "\u{1f468}\u{200d}\u{1f3eb}", 113 | ':man_technologist:' => "\u{1f468}\u{200d}\u{1f4bb}", 114 | ':man_tipping_hand:' => "\u{1f481}\u{200d}\u{2642}\u{fe0f}", 115 | ':man_vampire:' => "\u{1f9db}\u{200d}\u{2642}\u{fe0f}", 116 | ':man_with_turban:' => "\u{1f473}", 117 | ':man_wearing_turban:' => "\u{1f473}", 118 | ':man_with_chinese_cap:' => "\u{1f472}", 119 | ':man_with_gua_pi_mao:' => "\u{1f472}", 120 | ':man_zombie:' => "\u{1f9df}\u{200d}\u{2642}\u{fe0f}", 121 | 122 | ':woman_artist:' => "\u{1f469}\u{200d}\u{1f3a8}", 123 | ':woman_astronaut:' => "\u{1f469}\u{200d}\u{1f680}", 124 | ':woman_biking:' => "\u{1f6b4}\u{200d}\u{2640}\u{fe0f}", 125 | ':woman_bouncing_ball:' => "\u{26f9}\u{fe0f}\u{200d}\u{2640}\u{fe0f}", 126 | ':woman_bowing:' => "\u{1f647}\u{200d}\u{2640}\u{fe0f}", 127 | ':woman_cartwheeling:' => "\u{1f938}\u{200d}\u{2640}\u{fe0f}", 128 | ':woman_construction_worker:' => "\u{1f477}\u{200d}\u{2640}\u{fe0f}", 129 | ':woman_cook:' => "\u{1f469}\u{200d}\u{1f373}", 130 | ':woman_detective:' => "\u{1f575}\u{fe0f}\u{200d}\u{2640}\u{fe0f}", 131 | ':woman_facepalming:' => "\u{1f926}\u{200d}\u{2640}\u{fe0f}", 132 | ':woman_factory_worker:' => "\u{1f469}\u{200d}\u{1f3ed}", 133 | ':woman_farmer:' => "\u{1f469}\u{200d}\u{1f33e}", 134 | ':woman_fairy:' => "\u{1f9da}\u{200d}\u{2640}\u{fe0f}", 135 | ':woman_firefighter:' => "\u{1f469}\u{200d}\u{1f692}", 136 | ':woman_frowning:' => "\u{1f64d}", 137 | ':woman_genie:' => "\u{1f9de}\u{200d}\u{2640}\u{fe0f}", 138 | ':woman_gesturing_no:' => "\u{1f645}", 139 | ':woman_gesturing_ok:' => "\u{1f646}", 140 | ':woman_getting_face_massage:' => "\u{1f486}", 141 | ':woman_getting_haircut:' => "\u{1f487}", 142 | ':woman_golfing:' => "\u{1f3cc}\u{fe0f}\u{200d}\u{2640}\u{fe0f}", 143 | ':woman_guard:' => "\u{1f482}\u{200d}\u{2640}\u{fe0f}", 144 | ':woman_health_worker:' => "\u{1f469}\u{200d}\u{2695}\u{fe0f}", 145 | ':woman_judge:' => "\u{1f469}\u{200d}\u{2696}\u{fe0f}", 146 | ':woman_juggling:' => "\u{1f939}\u{200d}\u{2640}\u{fe0f}", 147 | ':woman_lifting_weights:' => "\u{1f3cb}\u{fe0f}\u{200d}\u{2640}\u{fe0f}", 148 | ':woman_mage:' => "\u{1f9d9}\u{200d}\u{2640}\u{fe0f}", 149 | ':woman_mechanic:' => "\u{1f469}\u{200d}\u{1f527}", 150 | ':woman_mountain_biking:' => "\u{1f6b5}\u{200d}\u{2640}\u{fe0f}", 151 | ':woman_office_worker:' => "\u{1f469}\u{200d}\u{1f4bc}", 152 | ':woman_pilot:' => "\u{1f469}\u{200d}\u{2708}\u{fe0f}", 153 | ':woman_playing_handball:' => "\u{1f93e}\u{200d}\u{2640}\u{fe0f}", 154 | ':woman_police_officer:' => "\u{1f46e}\u{200d}\u{2640}\u{fe0f}", 155 | ':woman_pouting:' => "\u{1f64e}", 156 | ':woman_raising_hand:' => "\u{1f64b}", 157 | ':woman_rowing_boat:' => "\u{1f6a3}\u{200d}\u{2640}\u{fe0f}", 158 | ':woman_running:' => "\u{1f3c3}\u{200d}\u{2640}\u{fe0f}", 159 | ':woman_scientist:' => "\u{1f469}\u{200d}\u{1f52c}", 160 | ':woman_shrugging:' => "\u{1f937}\u{200d}\u{2640}\u{fe0f}", 161 | ':woman_singer:' => "\u{1f469}\u{200d}\u{1f3a4}", 162 | ':woman_student:' => "\u{1f469}\u{200d}\u{1f393}", 163 | ':woman_teacher:' => "\u{1f469}\u{200d}\u{1f3eb}", 164 | ':woman_technologist:' => "\u{1f469}\u{200d}\u{1f4bb}", 165 | ':woman_tipping_hand:' => "\u{1f481}\u{1f3fc}", 166 | ':woman_vampire:' => "\u{1f9db}\u{200d}\u{2640}\u{fe0f}", 167 | ':woman_wearing_turban:' => "\u{1f473}\u{200d}\u{2640}\u{fe0f}", 168 | ':woman_zombie:' => "\u{1f9df}\u{200d}\u{2640}\u{fe0f}", 169 | 170 | ':cop:' => "\u{1f46e}", 171 | ':construction_worker:' => "\u{1f477}", 172 | ':guardsman:' => "\u{1f482}", 173 | ':baby:' => "\u{1f476}", 174 | ':boy:' => "\u{1f466}", 175 | ':girl:' => "\u{1f467}", 176 | ':man:' => "\u{1f468}", 177 | ':woman:' => "\u{1f469}", 178 | ':older_man:' => "\u{1f474}", 179 | ':older_woman:' => "\u{1f475}", 180 | ':person_with_blond_hair:' => "\u{1f471}", 181 | ':angel:' => "\u{1f47c}", 182 | ':princess:' => "\u{1f478}", 183 | ':smiley_cat:' => "\u{1f63a}", 184 | ':smile_cat:' => "\u{1f638}", 185 | ':heart_eyes_cat:' => "\u{1f63b}", 186 | ':kissing_cat:' => "\u{1f63d}", 187 | ':smirk_cat:' => "\u{1f63c}", 188 | ':scream_cat:' => "\u{1f640}", 189 | ':crying_cat_face:' => "\u{1f63f}", 190 | ':joy_cat:' => "\u{1f639}", 191 | ':pouting_cat:' => "\u{1f63e}", 192 | ':japanese_ogre:' => "\u{1f479}", 193 | ':japanese_goblin:' => "\u{1f47a}", 194 | ':see_no_evil:' => "\u{1f648}", 195 | ':hear_no_evil:' => "\u{1f649}", 196 | ':speak_no_evil:' => "\u{1f64a}", 197 | ':skull:' => "\u{1f480}", 198 | ':alien:' => "\u{1f47d}", 199 | ':hankey:' => "\u{1f4a9}", 200 | ':fire:' => "\u{1f525}", 201 | ':sparkles:' => "\u{2728}", 202 | ':comet:' => "\u{2604}\u{fe0f}", 203 | ':star2:' => "\u{1f31f}", 204 | ':dizzy:' => "\u{1f4ab}", 205 | ':boom:' => "\u{1f4a5}", 206 | ':anger:' => "\u{1f4a2}", 207 | ':sweat_drops:' => "\u{1f4a6}", 208 | ':droplet:' => "\u{1f4a7}", 209 | ':zzz:' => "\u{1f4a4}", 210 | ':dash:' => "\u{1f4a8}", 211 | ':ear:' => "\u{1f442}", 212 | ':eyes:' => "\u{1f440}", 213 | ':nose:' => "\u{1f443}", 214 | ':tongue:' => "\u{1f445}", 215 | ':lips:' => "\u{1f444}", 216 | ':sign_of_the_horns:' => "\u{1f918}", 217 | ':metal:' => "\u{1f918}", 218 | ':ok_hand:' => "\u{1f44c}", 219 | ':facepunch:' => "\u{1f44a}", 220 | ':punch:' => "\u{1f44a}", 221 | ':fist:' => "\u{270a}", 222 | ':v:' => "\u{270c}", 223 | ':wave:' => "\u{1f44b}", 224 | ':hand:' => "\u{270b}", 225 | ':open_hands:' => "\u{1f450}", 226 | ':point_up_2:' => "\u{1f446}", 227 | ':point_down:' => "\u{1f447}", 228 | ':point_right:' => "\u{1f449}", 229 | ':point_left:' => "\u{1f448}", 230 | ':thumbup:' => "\u{d83d}\u{dc4d}", 231 | ':thumbsup:' => "\u{d83d}\u{dc4d}", 232 | ':thumbdown:' => "\u{d83d}\u{dc4e}", 233 | ':thumbsdown:' => "\u{d83d}\u{dc4e}", 234 | ':raised_hands:' => "\u{1f64c}", 235 | ':pray:' => "\u{1f64f}", 236 | ':point_up:' => "\u{261d}", 237 | ':clap:' => "\u{1f44f}", 238 | ':muscle:' => "\u{1f4aa}", 239 | ':walking:' => "\u{1f6b6}", 240 | ':runner:' => "\u{1f3c3}", 241 | ':dancer:' => "\u{1f483}", 242 | ':couple:' => "\u{1f46b}", 243 | ':family:' => "\u{1f46a}", 244 | ':two_men_holding_hands:' => "\u{1f46c}", 245 | ':two_women_holding_hands:' => "\u{1f46d}", 246 | ':couplekiss:' => "\u{1f48f}", 247 | ':couple_with_heart:' => "\u{1f491}", 248 | ':dancers:' => "\u{1f46f}", 249 | ':ok_woman:' => "\u{1f646}", 250 | ':no_good:' => "\u{1f645}", 251 | ':information_desk_person:' => "\u{1f481}", 252 | ':raising_hand:' => "\u{1f64b}", 253 | ':massage:' => "\u{1f486}", 254 | ':haircut:' => "\u{1f487}", 255 | ':nail_care:' => "\u{1f485}", 256 | ':bride_with_veil:' => "\u{1f470}", 257 | ':person_with_pouting_face:' => "\u{1f64e}", 258 | ':person_frowning:' => "\u{1f64d}", 259 | ':bow:' => "\u{1f647}", 260 | ':tophat:' => "\u{1f3a9}", 261 | ':crown:' => "\u{1f451}", 262 | ':womans_hat:' => "\u{1f452}", 263 | ':athletic_shoe:' => "\u{1f45f}", 264 | ':mans_shoe:' => "\u{1f45e}", 265 | ':sandal:' => "\u{1f461}", 266 | ':high_heel:' => "\u{1f460}", 267 | ':boot:' => "\u{1f462}", 268 | ':shirt:' => "\u{1f455}", 269 | ':necktie:' => "\u{1f454}", 270 | ':womans_clothes:' => "\u{1f45a}", 271 | ':dress:' => "\u{1f457}", 272 | ':running_shirt_with_sash:' => "\u{1f3bd}", 273 | ':jeans:' => "\u{1f456}", 274 | ':kimono:' => "\u{1f458}", 275 | ':bikini:' => "\u{1f459}", 276 | ':briefcase:' => "\u{1f4bc}", 277 | ':handbag:' => "\u{1f45c}", 278 | ':pouch:' => "\u{1f45d}", 279 | ':purse:' => "\u{1f45b}", 280 | ':eyeglasses:' => "\u{1f453}", 281 | ':ribbon:' => "\u{1f380}", 282 | ':closed_umbrella:' => "\u{1f302}", 283 | ':lipstick:' => "\u{1f484}", 284 | ':yellow_heart:' => "\u{1f49b}", 285 | ':blue_heart:' => "\u{1f499}", 286 | ':purple_heart:' => "\u{1f49c}", 287 | ':green_heart:' => "\u{1f49a}", 288 | ':orange_heart:' => "\u{1f9e1}", 289 | ':black_heart:' => "\u{1f5a4}", 290 | ':heart:' => "\u{2764}", 291 | ':broken_heart:' => "\u{1f494}", 292 | ':heartpulse:' => "\u{1f497}", 293 | ':heartbeat:' => "\u{1f493}", 294 | ':two_hearts:' => "\u{1f495}", 295 | ':sparkling_heart:' => "\u{1f496}", 296 | ':revolving_hearts:' => "\u{1f49e}", 297 | ':cupid:' => "\u{1f498}", 298 | ':love_letter:' => "\u{1f48c}", 299 | ':kiss:' => "\u{1f48b}", 300 | ':ring:' => "\u{1f48d}", 301 | ':gem:' => "\u{1f48e}", 302 | ':bust_in_silhouette:' => "\u{1f464}", 303 | ':busts_in_silhouette:' => "\u{1f465}", 304 | ':speaking_head_in_silhouette:' => "\u{1f5e3}", 305 | ':speech_balloon:' => "\u{1f4ac}", 306 | ':footprints:' => "\u{1f463}", 307 | ':thought_balloon:' => "\u{1f4ad}", 308 | ':dog:' => "\u{1f436}", 309 | ':wolf:' => "\u{1f43a}", 310 | ':cat:' => "\u{1f431}", 311 | ':mouse:' => "\u{1f42d}", 312 | ':hamster:' => "\u{1f439}", 313 | ':rabbit:' => "\u{1f430}", 314 | ':frog:' => "\u{1f438}", 315 | ':tiger:' => "\u{1f42f}", 316 | ':koala:' => "\u{1f428}", 317 | ':bear:' => "\u{1f43b}", 318 | ':pig:' => "\u{1f437}", 319 | ':pig_nose:' => "\u{1f43d}", 320 | ':cow:' => "\u{1f42e}", 321 | ':boar:' => "\u{1f417}", 322 | ':monkey_face:' => "\u{1f435}", 323 | ':monkey:' => "\u{1f412}", 324 | ':horse:' => "\u{1f434}", 325 | ':sheep:' => "\u{1f411}", 326 | ':elephant:' => "\u{1f418}", 327 | ':panda_face:' => "\u{1f43c}", 328 | ':penguin:' => "\u{1f427}", 329 | ':bird:' => "\u{1f426}", 330 | ':baby_chick:' => "\u{1f424}", 331 | ':hatched_chick:' => "\u{1f425}", 332 | ':hatching_chick:' => "\u{1f423}", 333 | ':chicken:' => "\u{1f414}", 334 | ':snake:' => "\u{1f40d}", 335 | ':turtle:' => "\u{1f422}", 336 | ':bug:' => "\u{1f41b}", 337 | ':bee:' => "\u{1f41d}", 338 | ':ant:' => "\u{1f41c}", 339 | ':beetle:' => "\u{1f41e}", 340 | ':snail:' => "\u{1f40c}", 341 | ':octopus:' => "\u{1f419}", 342 | ':shell:' => "\u{1f41a}", 343 | ':tropical_fish:' => "\u{1f420}", 344 | ':fish:' => "\u{1f41f}", 345 | ':dolphin:' => "\u{1f42c}", 346 | ':whale:' => "\u{1f433}", 347 | ':whale2:' => "\u{1f40b}", 348 | ':cow2:' => "\u{1f404}", 349 | ':ram:' => "\u{1f40f}", 350 | ':rat:' => "\u{1f400}", 351 | ':water_buffalo:' => "\u{1f403}", 352 | ':tiger2:' => "\u{1f405}", 353 | ':rabbit2:' => "\u{1f407}", 354 | ':dragon:' => "\u{1f409}", 355 | ':racehorse:' => "\u{1f40e}", 356 | ':goat:' => "\u{1f410}", 357 | ':rooster:' => "\u{1f413}", 358 | ':dog2:' => "\u{1f415}", 359 | ':pig2:' => "\u{1f416}", 360 | ':mouse2:' => "\u{1f401}", 361 | ':ox:' => "\u{1f402}", 362 | ':dragon_face:' => "\u{1f432}", 363 | ':blowfish:' => "\u{1f421}", 364 | ':crocodile:' => "\u{1f40a}", 365 | ':camel:' => "\u{1f42b}", 366 | ':dromedary_camel:' => "\u{1f42a}", 367 | ':leopard:' => "\u{1f406}", 368 | ':cat2:' => "\u{1f408}", 369 | ':poodle:' => "\u{1f429}", 370 | ':feet:' => "\u{1f43e}", 371 | ':bouquet:' => "\u{1f490}", 372 | ':cherry_blossom:' => "\u{1f338}", 373 | ':tulip:' => "\u{1f337}", 374 | ':four_leaf_clover:' => "\u{1f340}", 375 | ':rose:' => "\u{1f339}", 376 | ':sunflower:' => "\u{1f33b}", 377 | ':hibiscus:' => "\u{1f33a}", 378 | ':maple_leaf:' => "\u{1f341}", 379 | ':leaves:' => "\u{1f343}", 380 | ':fallen_leaf:' => "\u{1f342}", 381 | ':herb:' => "\u{1f33f}", 382 | ':ear_of_rice:' => "\u{1f33e}", 383 | ':mushroom:' => "\u{1f344}", 384 | ':cactus:' => "\u{1f335}", 385 | ':palm_tree:' => "\u{1f334}", 386 | ':evergreen_tree:' => "\u{1f332}", 387 | ':deciduous_tree:' => "\u{1f333}", 388 | ':chestnut:' => "\u{1f330}", 389 | ':seedling:' => "\u{1f331}", 390 | ':blossom:' => "\u{1f33c}", 391 | ':globe_with_meridians:' => "\u{1f310}", 392 | ':sun_with_face:' => "\u{1f31e}", 393 | ':full_moon_with_face:' => "\u{1f31d}", 394 | ':new_moon_with_face:' => "\u{1f31a}", 395 | ':new_moon:' => "\u{1f311}", 396 | ':waxing_crescent_moon:' => "\u{1f312}", 397 | ':first_quarter_moon:' => "\u{1f313}", 398 | ':moon:' => "\u{1f314}", 399 | ':full_moon:' => "\u{1f315}", 400 | ':waning_gibbous_moon:' => "\u{1f316}", 401 | ':last_quarter_moon:' => "\u{1f317}", 402 | ':waning_crescent_moon:' => "\u{1f318}", 403 | ':last_quarter_moon_with_face:' => "\u{1f31c}", 404 | ':first_quarter_moon_with_face:' => "\u{1f31b}", 405 | ':crescent_moon:' => "\u{1f319}", 406 | ':earth_africa:' => "\u{1f30d}", 407 | ':earth_americas:' => "\u{1f30e}", 408 | ':earth_asia:' => "\u{1f30f}", 409 | ':volcano:' => "\u{1f30b}", 410 | ':milky_way:' => "\u{1f30c}", 411 | ':stars:' => "\u{1f320}", 412 | ':star:' => "\u{2b50}", 413 | ':sunny:' => "\u{2600}", 414 | ':partly_sunny:' => "\u{26c5}", 415 | ':cloud:' => "\u{2601}", 416 | ':zap:' => "\u{26a1}", 417 | ':umbrella:' => "\u{2614}", 418 | ':snowflake:' => "\u{2744}", 419 | ':snowman:' => "\u{26c4}", 420 | ':cyclone:' => "\u{1f300}", 421 | ':foggy:' => "\u{1f301}", 422 | ':rainbow:' => "\u{1f308}", 423 | ':rainbow_flag:' => "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", 424 | ':ocean:' => "\u{1f30a}", 425 | ':bamboo:' => "\u{1f38d}", 426 | ':gift_heart:' => "\u{1f49d}", 427 | ':dolls:' => "\u{1f38e}", 428 | ':school_satchel:' => "\u{1f392}", 429 | ':mortar_board:' => "\u{1f393}", 430 | ':flags:' => "\u{1f38f}", 431 | ':fireworks:' => "\u{1f386}", 432 | ':sparkler:' => "\u{1f387}", 433 | ':wind_chime:' => "\u{1f390}", 434 | ':rice_scene:' => "\u{1f391}", 435 | ':jack_o_lantern:' => "\u{1f383}", 436 | ':ghost:' => "\u{1f47b}", 437 | ':santa:' => "\u{1f385}", 438 | ':christmas_tree:' => "\u{1f384}", 439 | ':gift:' => "\u{1f381}", 440 | ':tanabata_tree:' => "\u{1f38b}", 441 | ':tada:' => "\u{1f389}", 442 | ':confetti_ball:' => "\u{1f38a}", 443 | ':balloon:' => "\u{1f388}", 444 | ':crossed_flags:' => "\u{1f38c}", 445 | ':crystal_ball:' => "\u{1f52e}", 446 | ':movie_camera:' => "\u{1f3a5}", 447 | ':camera:' => "\u{1f4f7}", 448 | ':video_camera:' => "\u{1f4f9}", 449 | ':vhs:' => "\u{1f4fc}", 450 | ':cd:' => "\u{1f4bf}", 451 | ':dvd:' => "\u{1f4c0}", 452 | ':minidisc:' => "\u{1f4bd}", 453 | ':floppy_disk:' => "\u{1f4be}", 454 | ':computer:' => "\u{1f4bb}", 455 | ':iphone:' => "\u{1f4f1}", 456 | ':phone:' => "\u{260e}", 457 | ':telephone_receiver:' => "\u{1f4de}", 458 | ':pager:' => "\u{1f4df}", 459 | ':fax:' => "\u{1f4e0}", 460 | ':satellite:' => "\u{1f4e1}", 461 | ':tv:' => "\u{1f4fa}", 462 | ':radio:' => "\u{1f4fb}", 463 | ':loud_sound:' => "\u{1f50a}", 464 | ':sound:' => "\u{1f509}", 465 | ':speaker:' => "\u{1f508}", 466 | ':mute:' => "\u{1f507}", 467 | ':bell:' => "\u{1f514}", 468 | ':no_bell:' => "\u{1f515}", 469 | ':mega:' => "\u{1f4e3}", 470 | ':loudspeaker:' => "\u{1f4e2}", 471 | ':hourglass_flowing_sand:' => "\u{23f3}", 472 | ':hourglass:' => "\u{231b}", 473 | ':alarm_clock:' => "\u{23f0}", 474 | ':watch:' => "\u{231a}", 475 | ':unlock:' => "\u{1f513}", 476 | ':lock:' => "\u{1f512}", 477 | ':lock_with_ink_pen:' => "\u{1f50f}", 478 | ':closed_lock_with_key:' => "\u{1f510}", 479 | ':key:' => "\u{1f511}", 480 | ':key2:' => "\u{1f5dd}", 481 | ':shit:' => "\u{1f4a9}", 482 | ':unicorn:' => "\u{1f984}", 483 | ':robot:' => "\u{1f916}", 484 | ':mag_right:' => "\u{1f50e}", 485 | ':bulb:' => "\u{1f4a1}", 486 | ':flashlight:' => "\u{1f526}", 487 | ':high_brightness:' => "\u{1f506}", 488 | ':low_brightness:' => "\u{1f505}", 489 | ':electric_plug:' => "\u{1f50c}", 490 | ':battery:' => "\u{1f50b}", 491 | ':mag:' => "\u{1f50d}", 492 | ':bath:' => "\u{1f6c0}", 493 | ':bathtub:' => "\u{1f6c1}", 494 | ':shower:' => "\u{1f6bf}", 495 | ':toilet:' => "\u{1f6bd}", 496 | ':wrench:' => "\u{1f527}", 497 | ':nut_and_bolt:' => "\u{1f529}", 498 | ':hammer:' => "\u{1f528}", 499 | ':door:' => "\u{1f6aa}", 500 | ':smoking:' => "\u{1f6ac}", 501 | ':bomb:' => "\u{1f4a3}", 502 | ':gun:' => "\u{1f52b}", 503 | ':hocho:' => "\u{1f52a}", 504 | ':pill:' => "\u{1f48a}", 505 | ':syringe:' => "\u{1f489}", 506 | ':moneybag:' => "\u{1f4b0}", 507 | ':yen:' => "\u{1f4b4}", 508 | ':dollar:' => "\u{1f4b5}", 509 | ':pound:' => "\u{1f4b7}", 510 | ':euro:' => "\u{1f4b6}", 511 | ':credit_card:' => "\u{1f4b3}", 512 | ':money_with_wings:' => "\u{1f4b8}", 513 | ':calling:' => "\u{1f4f2}", 514 | ':e-mail:' => "\u{1f4e7}", 515 | ':inbox_tray:' => "\u{1f4e5}", 516 | ':outbox_tray:' => "\u{1f4e4}", 517 | ':email:' => "\u{2709}", 518 | ':envelope_with_arrow:' => "\u{1f4e9}", 519 | ':incoming_envelope:' => "\u{1f4e8}", 520 | ':postal_horn:' => "\u{1f4ef}", 521 | ':mailbox:' => "\u{1f4eb}", 522 | ':mailbox_closed:' => "\u{1f4ea}", 523 | ':mailbox_with_mail:' => "\u{1f4ec}", 524 | ':mailbox_with_no_mail:' => "\u{1f4ed}", 525 | ':postbox:' => "\u{1f4ee}", 526 | ':package:' => "\u{1f4e6}", 527 | ':memo:' => "\u{1f4dd}", 528 | ':pencil:' => "\u{1f4dd}", 529 | ':page_facing_up:' => "\u{1f4c4}", 530 | ':page_with_curl:' => "\u{1f4c3}", 531 | ':bookmark_tabs:' => "\u{1f4d1}", 532 | ':bar_chart:' => "\u{1f4ca}", 533 | ':chart_with_upwards_trend:' => "\u{1f4c8}", 534 | ':chart_with_downwards_trend:' => "\u{1f4c9}", 535 | ':scroll:' => "\u{1f4dc}", 536 | ':clipboard:' => "\u{1f4cb}", 537 | ':date:' => "\u{1f4c5}", 538 | ':calendar:' => "\u{1f4c6}", 539 | ':card_index:' => "\u{1f4c7}", 540 | ':file_folder:' => "\u{1f4c1}", 541 | ':open_file_folder:' => "\u{1f4c2}", 542 | ':scissors:' => "\u{2702}", 543 | ':pushpin:' => "\u{1f4cc}", 544 | ':paperclip:' => "\u{1f4ce}", 545 | ':black_nib:' => "\u{2712}", 546 | ':pencil2:' => "\u{270f}", 547 | ':straight_ruler:' => "\u{1f4cf}", 548 | ':triangular_ruler:' => "\u{1f4d0}", 549 | ':closed_book:' => "\u{1f4d5}", 550 | ':green_book:' => "\u{1f4d7}", 551 | ':blue_book:' => "\u{1f4d8}", 552 | ':orange_book:' => "\u{1f4d9}", 553 | ':notebook:' => "\u{1f4d3}", 554 | ':notebook_with_decorative_cover:' => "\u{1f4d4}", 555 | ':ledger:' => "\u{1f4d2}", 556 | ':books:' => "\u{1f4da}", 557 | ':book:' => "\u{1f4d6}", 558 | ':bookmark:' => "\u{1f516}", 559 | ':name_badge:' => "\u{1f4db}", 560 | ':microscope:' => "\u{1f52c}", 561 | ':telescope:' => "\u{1f52d}", 562 | ':newspaper:' => "\u{1f4f0}", 563 | ':art:' => "\u{1f3a8}", 564 | ':clapper:' => "\u{1f3ac}", 565 | ':microphone:' => "\u{1f3a4}", 566 | ':headphones:' => "\u{1f3a7}", 567 | ':musical_score:' => "\u{1f3bc}", 568 | ':musical_note:' => "\u{1f3b5}", 569 | ':notes:' => "\u{1f3b6}", 570 | ':musical_keyboard:' => "\u{1f3b9}", 571 | ':violin:' => "\u{1f3bb}", 572 | ':trumpet:' => "\u{1f3ba}", 573 | ':saxophone:' => "\u{1f3b7}", 574 | ':guitar:' => "\u{1f3b8}", 575 | ':space_invader:' => "\u{1f47e}", 576 | ':video_game:' => "\u{1f3ae}", 577 | ':black_joker:' => "\u{1f0cf}", 578 | ':flower_playing_cards:' => "\u{1f3b4}", 579 | ':mahjong:' => "\u{1f004}", 580 | ':game_die:' => "\u{1f3b2}", 581 | ':dart:' => "\u{1f3af}", 582 | ':football:' => "\u{1f3c8}", 583 | ':basketball:' => "\u{1f3c0}", 584 | ':soccer:' => "\u{26bd}", 585 | ':baseball:' => "\u{26be}", 586 | ':tennis:' => "\u{1f3be}", 587 | ':8ball:' => "\u{1f3b1}", 588 | ':rugby_football:' => "\u{1f3c9}", 589 | ':bowling:' => "\u{1f3b3}", 590 | ':golf:' => "\u{26f3}", 591 | ':mountain_bicyclist:' => "\u{1f6b5}", 592 | ':bicyclist:' => "\u{1f6b4}", 593 | ':checkered_flag:' => "\u{1f3c1}", 594 | ':horse_racing:' => "\u{1f3c7}", 595 | ':trophy:' => "\u{1f3c6}", 596 | ':ski:' => "\u{1f3bf}", 597 | ':snowboarder:' => "\u{1f3c2}", 598 | ':swimmer:' => "\u{1f3ca}", 599 | ':surfer:' => "\u{1f3c4}", 600 | ':fishing_pole_and_fish:' => "\u{1f3a3}", 601 | ':coffee:' => "\u{2615}", 602 | ':tea:' => "\u{1f375}", 603 | ':sake:' => "\u{1f376}", 604 | ':baby_bottle:' => "\u{1f37c}", 605 | ':beer:' => "\u{1f37a}", 606 | ':beers:' => "\u{1f37b}", 607 | ':cocktail:' => "\u{1f378}", 608 | ':tropical_drink:' => "\u{1f379}", 609 | ':wine_glass:' => "\u{1f377}", 610 | ':fork_and_knife:' => "\u{1f374}", 611 | ':pizza:' => "\u{1f355}", 612 | ':hamburger:' => "\u{1f354}", 613 | ':fries:' => "\u{1f35f}", 614 | ':poultry_leg:' => "\u{1f357}", 615 | ':meat_on_bone:' => "\u{1f356}", 616 | ':spaghetti:' => "\u{1f35d}", 617 | ':curry:' => "\u{1f35b}", 618 | ':fried_shrimp:' => "\u{1f364}", 619 | ':bento:' => "\u{1f371}", 620 | ':sushi:' => "\u{1f363}", 621 | ':fish_cake:' => "\u{1f365}", 622 | ':rice_ball:' => "\u{1f359}", 623 | ':rice_cracker:' => "\u{1f358}", 624 | ':rice:' => "\u{1f35a}", 625 | ':ramen:' => "\u{1f35c}", 626 | ':stew:' => "\u{1f372}", 627 | ':oden:' => "\u{1f362}", 628 | ':dango:' => "\u{1f361}", 629 | ':egg:' => "\u{1f373}", 630 | ':bread:' => "\u{1f35e}", 631 | ':doughnut:' => "\u{1f369}", 632 | ':custard:' => "\u{1f36e}", 633 | ':icecream:' => "\u{1f366}", 634 | ':ice_cream:' => "\u{1f368}", 635 | ':shaved_ice:' => "\u{1f367}", 636 | ':birthday:' => "\u{1f382}", 637 | ':cake:' => "\u{1f370}", 638 | ':cookie:' => "\u{1f36a}", 639 | ':chocolate_bar:' => "\u{1f36b}", 640 | ':candy:' => "\u{1f36c}", 641 | ':lollipop:' => "\u{1f36d}", 642 | ':honey_pot:' => "\u{1f36f}", 643 | ':apple:' => "\u{1f34e}", 644 | ':green_apple:' => "\u{1f34f}", 645 | ':tangerine:' => "\u{1f34a}", 646 | ':lemon:' => "\u{1f34b}", 647 | ':cherries:' => "\u{1f352}", 648 | ':grapes:' => "\u{1f347}", 649 | ':watermelon:' => "\u{1f349}", 650 | ':strawberry:' => "\u{1f353}", 651 | ':peach:' => "\u{1f351}", 652 | ':melon:' => "\u{1f348}", 653 | ':banana:' => "\u{1f34c}", 654 | ':pear:' => "\u{1f350}", 655 | ':pineapple:' => "\u{1f34d}", 656 | ':sweet_potato:' => "\u{1f360}", 657 | ':eggplant:' => "\u{1f346}", 658 | ':tomato:' => "\u{1f345}", 659 | ':corn:' => "\u{1f33d}", 660 | ':house:' => "\u{1f3e0}", 661 | ':house_with_garden:' => "\u{1f3e1}", 662 | ':school:' => "\u{1f3eb}", 663 | ':office:' => "\u{1f3e2}", 664 | ':post_office:' => "\u{1f3e3}", 665 | ':hospital:' => "\u{1f3e5}", 666 | ':bank:' => "\u{1f3e6}", 667 | ':convenience_store:' => "\u{1f3ea}", 668 | ':love_hotel:' => "\u{1f3e9}", 669 | ':hotel:' => "\u{1f3e8}", 670 | ':wedding:' => "\u{1f492}", 671 | ':church:' => "\u{26ea}", 672 | ':department_store:' => "\u{1f3ec}", 673 | ':european_post_office:' => "\u{1f3e4}", 674 | ':city_sunrise:' => "\u{1f307}", 675 | ':city_sunset:' => "\u{1f306}", 676 | ':japanese_castle:' => "\u{1f3ef}", 677 | ':european_castle:' => "\u{1f3f0}", 678 | ':tent:' => "\u{26fa}", 679 | ':factory:' => "\u{1f3ed}", 680 | ':tokyo_tower:' => "\u{1f5fc}", 681 | ':japan:' => "\u{1f5fe}", 682 | ':mount_fuji:' => "\u{1f5fb}", 683 | ':sunrise_over_mountains:' => "\u{1f304}", 684 | ':sunrise:' => "\u{1f305}", 685 | ':night_with_stars:' => "\u{1f303}", 686 | ':statue_of_liberty:' => "\u{1f5fd}", 687 | ':bridge_at_night:' => "\u{1f309}", 688 | ':carousel_horse:' => "\u{1f3a0}", 689 | ':ferris_wheel:' => "\u{1f3a1}", 690 | ':fountain:' => "\u{26f2}", 691 | ':roller_coaster:' => "\u{1f3a2}", 692 | ':ship:' => "\u{1f6a2}", 693 | ':boat:' => "\u{26f5}", 694 | ':speedboat:' => "\u{1f6a4}", 695 | ':rowboat:' => "\u{1f6a3}", 696 | ':anchor:' => "\u{2693}", 697 | ':rocket:' => "\u{1f680}", 698 | ':airplane:' => "\u{2708}", 699 | ':seat:' => "\u{1f4ba}", 700 | ':helicopter:' => "\u{1f681}", 701 | ':steam_locomotive:' => "\u{1f682}", 702 | ':tram:' => "\u{1f68a}", 703 | ':station:' => "\u{1f689}", 704 | ':mountain_railway:' => "\u{1f69e}", 705 | ':train2:' => "\u{1f686}", 706 | ':bullettrain_side:' => "\u{1f684}", 707 | ':bullettrain_front:' => "\u{1f685}", 708 | ':light_rail:' => "\u{1f688}", 709 | ':metro:' => "\u{1f687}", 710 | ':monorail:' => "\u{1f69d}", 711 | ':railway_car:' => "\u{1f683}", 712 | ':train:' => "\u{1f68b}", 713 | ':trolleybus:' => "\u{1f68e}", 714 | ':bus:' => "\u{1f68c}", 715 | ':oncoming_bus:' => "\u{1f68d}", 716 | ':blue_car:' => "\u{1f699}", 717 | ':oncoming_automobile:' => "\u{1f698}", 718 | ':car:' => "\u{1f697}", 719 | ':taxi:' => "\u{1f695}", 720 | ':oncoming_taxi:' => "\u{1f696}", 721 | ':articulated_lorry:' => "\u{1f69b}", 722 | ':truck:' => "\u{1f69a}", 723 | ':rotating_light:' => "\u{1f6a8}", 724 | ':police_car:' => "\u{1f693}", 725 | ':oncoming_police_car:' => "\u{1f694}", 726 | ':fire_engine:' => "\u{1f692}", 727 | ':ambulance:' => "\u{1f691}", 728 | ':minibus:' => "\u{1f690}", 729 | ':bike:' => "\u{1f6b2}", 730 | ':aerial_tramway:' => "\u{1f6a1}", 731 | ':suspension_railway:' => "\u{1f69f}", 732 | ':mountain_cableway:' => "\u{1f6a0}", 733 | ':tractor:' => "\u{1f69c}", 734 | ':barber:' => "\u{1f488}", 735 | ':busstop:' => "\u{1f68f}", 736 | ':ticket:' => "\u{1f3ab}", 737 | ':vertical_traffic_light:' => "\u{1f6a6}", 738 | ':traffic_light:' => "\u{1f6a5}", 739 | ':warning:' => "\u{26a0}", 740 | ':construction:' => "\u{1f6a7}", 741 | ':beginner:' => "\u{1f530}", 742 | ':fuelpump:' => "\u{26fd}", 743 | ':izakaya_lantern:' => "\u{1f3ee}", 744 | ':slot_machine:' => "\u{1f3b0}", 745 | ':hotsprings:' => "\u{2668}", 746 | ':moyai:' => "\u{1f5ff}", 747 | ':circus_tent:' => "\u{1f3aa}", 748 | ':performing_arts:' => "\u{1f3ad}", 749 | ':round_pushpin:' => "\u{1f4cd}", 750 | ':triangular_flag_on_post:' => "\u{1f6a9}", 751 | ':one:' => "\u{0031}", 752 | ':two:' => "\u{0032}", 753 | ':three:' => "\u{0033}", 754 | ':four:' => "\u{0034}", 755 | ':five:' => "\u{0035}", 756 | ':six:' => "\u{0036}", 757 | ':seven:' => "\u{0037}", 758 | ':eight:' => "\u{0038}", 759 | ':nine:' => "\u{0039}", 760 | ':zero:' => "\u{0030}", 761 | ':keycap_ten:' => "\u{1f51f}", 762 | ':1234:' => "\u{1f522}", 763 | ':hash:' => "\u{0023}", 764 | ':symbols:' => "\u{1f523}", 765 | ':arrow_up:' => "\u{2b06}", 766 | ':arrow_down:' => "\u{2b07}", 767 | ':arrow_left:' => "\u{2b05}", 768 | ':arrow_right:' => "\u{27a1}", 769 | ':capital_abcd:' => "\u{1f520}", 770 | ':abcd:' => "\u{1f521}", 771 | ':abc:' => "\u{1f524}", 772 | ':arrow_upper_right:' => "\u{2197}", 773 | ':arrow_upper_left:' => "\u{2196}", 774 | ':arrow_lower_right:' => "\u{2198}", 775 | ':arrow_lower_left:' => "\u{2199}", 776 | ':left_right_arrow:' => "\u{2194}", 777 | ':arrow_up_down:' => "\u{2195}", 778 | ':arrows_counterclockwise:' => "\u{1f504}", 779 | ':arrow_backward:' => "\u{25c0}", 780 | ':arrow_forward:' => "\u{25b6}", 781 | ':play_pause:' => "\u{23ef}\u{fe0f}", 782 | ':arrow_up_small:' => "\u{1f53c}", 783 | ':arrow_down_small:' => "\u{1f53d}", 784 | ':leftwards_arrow_with_hook:' => "\u{21a9}", 785 | ':arrow_right_hook:' => "\u{21aa}", 786 | ':information_source:' => "\u{2139}", 787 | ':rewind:' => "\u{23ea}", 788 | ':fast_forward:' => "\u{23e9}", 789 | ':arrow_double_up:' => "\u{23eb}", 790 | ':arrow_double_down:' => "\u{23ec}", 791 | ':arrow_heading_down:' => "\u{2935}", 792 | ':arrow_heading_up:' => "\u{2934}", 793 | ':ok:' => "\u{1f197}", 794 | ':twisted_rightwards_arrows:' => "\u{1f500}", 795 | ':repeat:' => "\u{1f501}", 796 | ':repeat_one:' => "\u{1f502}", 797 | ':new:' => "\u{1f195}", 798 | ':up:' => "\u{1f199}", 799 | ':cool:' => "\u{1f192}", 800 | ':free:' => "\u{1f193}", 801 | ':ng:' => "\u{1f196}", 802 | ':signal_strength:' => "\u{1f4f6}", 803 | ':cinema:' => "\u{1f3a6}", 804 | ':koko:' => "\u{1f201}", 805 | ':ideograph_advantage:' => "\u{1f250}", 806 | ':restroom:' => "\u{1f6bb}", 807 | ':mens:' => "\u{1f6b9}", 808 | ':womens:' => "\u{1f6ba}", 809 | ':baby_symbol:' => "\u{1f6bc}", 810 | ':wc:' => "\u{1f6be}", 811 | ':potable_water:' => "\u{1f6b0}", 812 | ':put_litter_in_its_place:' => "\u{1f6ae}", 813 | ':parking:' => "\u{1f17f}", 814 | ':wheelchair:' => "\u{267f}", 815 | ':no_smoking:' => "\u{1f6ad}", 816 | ':u6708:' => "\u{1f237}", 817 | ':u7533:' => "\u{1f238}", 818 | ':sa:' => "\u{1f202}", 819 | ':m:' => "\u{24c2}", 820 | ':passport_control:' => "\u{1f6c2}", 821 | ':baggage_claim:' => "\u{1f6c4}", 822 | ':left_luggage:' => "\u{1f6c5}", 823 | ':customs:' => "\u{1f6c3}", 824 | ':accept:' => "\u{1f251}", 825 | ':secret:' => "\u{3299}", 826 | ':congratulations:' => "\u{3297}", 827 | ':cl:' => "\u{1f191}", 828 | ':sos:' => "\u{1f198}", 829 | ':id:' => "\u{1f194}", 830 | ':no_entry_sign:' => "\u{1f6ab}", 831 | ':underage:' => "\u{1f51e}", 832 | ':no_mobile_phones:' => "\u{1f4f5}", 833 | ':do_not_litter:' => "\u{1f6af}", 834 | ':non_potable_water:' => "\u{1f6b1}", 835 | ':no_bicycles:' => "\u{1f6b3}", 836 | ':no_pedestrians:' => "\u{1f6b7}", 837 | ':children_crossing:' => "\u{1f6b8}", 838 | ':no_entry:' => "\u{26d4}", 839 | ':eight_spoked_asterisk:' => "\u{2733}", 840 | ':sparkle:' => "\u{2747}", 841 | ':negative_squared_cross_mark:' => "\u{274e}", 842 | ':white_check_mark:' => "\u{2705}", 843 | ':eight_pointed_black_star:' => "\u{2734}", 844 | ':heart_decoration:' => "\u{1f49f}", 845 | ':vs:' => "\u{1f19a}", 846 | ':vibration_mode:' => "\u{1f4f3}", 847 | ':mobile_phone_off:' => "\u{1f4f4}", 848 | ':a:' => "\u{1f170}", 849 | ':b:' => "\u{1f171}", 850 | ':ab:' => "\u{1f18e}", 851 | ':o2:' => "\u{1f17e}", 852 | ':diamond_shape_with_a_dot_inside:' => "\u{1f4a0}", 853 | ':loop:' => "\u{27bf}", 854 | ':recycle:' => "\u{267b}", 855 | ':aries:' => "\u{2648}", 856 | ':taurus:' => "\u{2649}", 857 | ':gemini:' => "\u{264a}", 858 | ':cancer:' => "\u{264b}", 859 | ':leo:' => "\u{264c}", 860 | ':virgo:' => "\u{264d}", 861 | ':libra:' => "\u{264e}", 862 | ':scorpius:' => "\u{264f}", 863 | ':sagittarius:' => "\u{2650}", 864 | ':capricorn:' => "\u{2651}", 865 | ':aquarius:' => "\u{2652}", 866 | ':pisces:' => "\u{2653}", 867 | ':ophiuchus:' => "\u{26ce}", 868 | ':six_pointed_star:' => "\u{1f52f}", 869 | ':atm:' => "\u{1f3e7}", 870 | ':chart:' => "\u{1f4b9}", 871 | ':heavy_dollar_sign:' => "\u{1f4b2}", 872 | ':currency_exchange:' => "\u{1f4b1}", 873 | ':copyright:' => "\u{00a9}", 874 | ':registered:' => "\u{00ae}", 875 | ':tm:' => "\u{2122}", 876 | ':x:' => "\u{274c}", 877 | ':bangbang:' => "\u{203c}", 878 | ':interrobang:' => "\u{2049}", 879 | ':exclamation:' => "\u{2757}", 880 | ':question:' => "\u{2753}", 881 | ':grey_exclamation:' => "\u{2755}", 882 | ':grey_question:' => "\u{2754}", 883 | ':o:' => "\u{2b55}", 884 | ':top:' => "\u{1f51d}", 885 | ':end:' => "\u{1f51a}", 886 | ':back:' => "\u{1f519}", 887 | ':on:' => "\u{1f51b}", 888 | ':soon:' => "\u{1f51c}", 889 | ':arrows_clockwise:' => "\u{1f503}", 890 | ':clock12:' => "\u{1f55b}", 891 | ':clock1230:' => "\u{1f567}", 892 | ':clock1:' => "\u{1f550}", 893 | ':clock130:' => "\u{1f55c}", 894 | ':clock2:' => "\u{1f551}", 895 | ':clock230:' => "\u{1f55d}", 896 | ':clock3:' => "\u{1f552}", 897 | ':clock330:' => "\u{1f55e}", 898 | ':clock4:' => "\u{1f553}", 899 | ':clock430:' => "\u{1f55f}", 900 | ':clock5:' => "\u{1f554}", 901 | ':clock530:' => "\u{1f560}", 902 | ':clock6:' => "\u{1f555}", 903 | ':clock7:' => "\u{1f556}", 904 | ':clock8:' => "\u{1f557}", 905 | ':clock9:' => "\u{1f558}", 906 | ':clock10:' => "\u{1f559}", 907 | ':clock11:' => "\u{1f55a}", 908 | ':clock630:' => "\u{1f561}", 909 | ':clock730:' => "\u{1f562}", 910 | ':clock830:' => "\u{1f563}", 911 | ':clock930:' => "\u{1f564}", 912 | ':clock1030:' => "\u{1f565}", 913 | ':clock1130:' => "\u{1f566}", 914 | ':heavy_multiplication_x:' => "\u{2716}", 915 | ':heavy_plus_sign:' => "\u{2795}", 916 | ':heavy_minus_sign:' => "\u{2796}", 917 | ':heavy_division_sign:' => "\u{2797}", 918 | ':spades:' => "\u{2660}", 919 | ':hearts:' => "\u{2665}", 920 | ':clubs:' => "\u{2663}", 921 | ':diamonds:' => "\u{2666}", 922 | ':white_flower:' => "\u{1f4ae}", 923 | ':100:' => "\u{1f4af}", 924 | ':heavy_check_mark:' => "\u{2714}", 925 | ':ballot_box_with_check:' => "\u{2611}", 926 | ':radio_button:' => "\u{1f518}", 927 | ':link:' => "\u{1f517}", 928 | ':curly_loop:' => "\u{27b0}", 929 | ':wavy_dash:' => "\u{3030}", 930 | ':part_alternation_mark:' => "\u{303d}", 931 | ':trident:' => "\u{1f531}", 932 | ':black_medium_square:' => "\u{25fc}", 933 | ':white_medium_square:' => "\u{25fb}", 934 | ':black_medium_small_square:' => "\u{25fe}", 935 | ':white_medium_small_square:' => "\u{25fd}", 936 | ':black_small_square:' => "\u{25aa}", 937 | ':white_small_square:' => "\u{25ab}", 938 | ':small_red_triangle:' => "\u{1f53a}", 939 | ':black_square_button:' => "\u{1f532}", 940 | ':white_square_button:' => "\u{1f533}", 941 | ':black_circle:' => "\u{26ab}", 942 | ':white_circle:' => "\u{26aa}", 943 | ':red_circle:' => "\u{1f534}", 944 | ':large_blue_circle:' => "\u{1f535}", 945 | ':small_red_triangle_down:' => "\u{1f53b}", 946 | ':white_large_square:' => "\u{2b1c}", 947 | ':black_large_square:' => "\u{2b1b}", 948 | ':large_orange_diamond:' => "\u{1f536}", 949 | ':large_blue_diamond:' => "\u{1f537}", 950 | ':small_orange_diamond:' => "\u{1f538}", 951 | ':small_blue_diamond:' => "\u{1f539}", 952 | 953 | // Countries 954 | ':flag_ad:' => "\u{1f1e6}\u{1f1e9}", 955 | ':flag_ae:' => "\u{1f1e6}\u{1f1ea}", 956 | ':flag_af:' => "\u{1f1e6}\u{1f1eb}", 957 | ':flag_ag:' => "\u{1f1e6}\u{1f1ec}", 958 | ':flag_ai:' => "\u{1f1e6}\u{1f1ee}", 959 | ':flag_al:' => "\u{1f1e6}\u{1f1f1}", 960 | ':flag_am:' => "\u{1f1e6}\u{1f1f2}", 961 | ':flag_ao:' => "\u{1f1e6}\u{1f1f4}", 962 | ':flag_aq:' => "\u{1f1e6}\u{1f1f6}", 963 | ':flag_ar:' => "\u{1f1e6}\u{1f1f7}", 964 | ':flag_as:' => "\u{1f1e6}\u{1f1f8}", 965 | ':flag_at:' => "\u{1f1e6}\u{1f1f9}", 966 | ':flag_au:' => "\u{1f1e6}\u{1f1fa}", 967 | ':flag_aw:' => "\u{1f1e6}\u{1f1fc}", 968 | ':flag_ax:' => "\u{1f1e6}\u{1f1fd}", 969 | ':flag_az:' => "\u{1f1e6}\u{1f1ff}", 970 | ':flag_ba:' => "\u{1f1e7}\u{1f1e6}", 971 | ':flag_bb:' => "\u{1f1e7}\u{1f1e7}", 972 | ':flag_bd:' => "\u{1f1e7}\u{1f1e9}", 973 | ':flag_be:' => "\u{1f1e7}\u{1f1ea}", 974 | ':flag_bf:' => "\u{1f1e7}\u{1f1eb}", 975 | ':flag_bg:' => "\u{1f1e7}\u{1f1ec}", 976 | ':flag_bh:' => "\u{1f1e7}\u{1f1ed}", 977 | ':flag_bi:' => "\u{1f1e7}\u{1f1ee}", 978 | ':flag_bj:' => "\u{1f1e7}\u{1f1ef}", 979 | ':flag_bl:' => "\u{1f1e7}\u{1f1f1}", 980 | ':flag_bm:' => "\u{1f1e7}\u{1f1f2}", 981 | ':flag_bn:' => "\u{1f1e7}\u{1f1f3}", 982 | ':flag_bo:' => "\u{1f1e7}\u{1f1f4}", 983 | ':flag_bq:' => "\u{1f1e7}\u{1f1f6}", 984 | ':flag_br:' => "\u{1f1e7}\u{1f1f7}", 985 | ':flag_bs:' => "\u{1f1e7}\u{1f1f8}", 986 | ':flag_bt:' => "\u{1f1e7}\u{1f1f9}", 987 | ':flag_bv:' => "\u{1f1e7}\u{1f1fb}", 988 | ':flag_bw:' => "\u{1f1e7}\u{1f1fc}", 989 | ':flag_by:' => "\u{1f1e7}\u{1f1fe}", 990 | ':flag_bz:' => "\u{1f1e7}\u{1f1ff}", 991 | ':flag_ca:' => "\u{1f1e8}\u{1f1e6}", 992 | ':flag_cc:' => "\u{1f1e8}\u{1f1e8}", 993 | ':flag_cd:' => "\u{1f1e8}\u{1f1e9}", 994 | ':flag_cf:' => "\u{1f1e8}\u{1f1eb}", 995 | ':flag_cg:' => "\u{1f1e8}\u{1f1ec}", 996 | ':flag_ch:' => "\u{1f1e8}\u{1f1ed}", 997 | ':flag_ci:' => "\u{1f1e8}\u{1f1ee}", 998 | ':flag_ck:' => "\u{1f1e8}\u{1f1f0}", 999 | ':flag_cl:' => "\u{1f1e8}\u{1f1f1}", 1000 | ':flag_cm:' => "\u{1f1e8}\u{1f1f2}", 1001 | ':flag_cn:' => "\u{1f1e8}\u{1f1f3}", 1002 | ':flag_co:' => "\u{1f1e8}\u{1f1f4}", 1003 | ':flag_cr:' => "\u{1f1e8}\u{1f1f7}", 1004 | ':flag_cu:' => "\u{1f1e8}\u{1f1fa}", 1005 | ':flag_cv:' => "\u{1f1e8}\u{1f1fb}", 1006 | ':flag_cw:' => "\u{1f1e8}\u{1f1fc}", 1007 | ':flag_cx:' => "\u{1f1e8}\u{1f1fd}", 1008 | ':flag_cy:' => "\u{1f1e8}\u{1f1fe}", 1009 | ':flag_cz:' => "\u{1f1e8}\u{1f1ff}", 1010 | ':flag_de:' => "\u{1f1e9}\u{1f1ea}", 1011 | ':flag_dj:' => "\u{1f1e9}\u{1f1ef}", 1012 | ':flag_dk:' => "\u{1f1e9}\u{1f1f0}", 1013 | ':flag_dm:' => "\u{1f1e9}\u{1f1f2}", 1014 | ':flag_do:' => "\u{1f1e9}\u{1f1f4}", 1015 | ':flag_dz:' => "\u{1f1e9}\u{1f1ff}", 1016 | ':flag_ec:' => "\u{1f1ea}\u{1f1e8}", 1017 | ':flag_ee:' => "\u{1f1ea}\u{1f1ea}", 1018 | ':flag_eg:' => "\u{1f1ea}\u{1f1ec}", 1019 | ':flag_eh:' => "\u{1f1ea}\u{1f1ed}", 1020 | ':flag_er:' => "\u{1f1ea}\u{1f1f7}", 1021 | ':flag_es:' => "\u{1f1ea}\u{1f1f8}", 1022 | ':flag_et:' => "\u{1f1ea}\u{1f1f9}", 1023 | ':flag_fi:' => "\u{1f1eb}\u{1f1ee}", 1024 | ':flag_fj:' => "\u{1f1eb}\u{1f1ef}", 1025 | ':flag_fk:' => "\u{1f1eb}\u{1f1f0}", 1026 | ':flag_fm:' => "\u{1f1eb}\u{1f1f2}", 1027 | ':flag_fo:' => "\u{1f1eb}\u{1f1f4}", 1028 | ':flag_fr:' => "\u{1f1eb}\u{1f1f7}", 1029 | ':flag_ga:' => "\u{1f1ec}\u{1f1e6}", 1030 | ':flag_gb:' => "\u{1f1ec}\u{1f1e7}", 1031 | ':flag_gd:' => "\u{1f1ec}\u{1f1e9}", 1032 | ':flag_ge:' => "\u{1f1ec}\u{1f1ea}", 1033 | ':flag_gf:' => "\u{1f1ec}\u{1f1eb}", 1034 | ':flag_gg:' => "\u{1f1ec}\u{1f1ec}", 1035 | ':flag_gh:' => "\u{1f1ec}\u{1f1ed}", 1036 | ':flag_gi:' => "\u{1f1ec}\u{1f1ee}", 1037 | ':flag_gl:' => "\u{1f1ec}\u{1f1f1}", 1038 | ':flag_gm:' => "\u{1f1ec}\u{1f1f2}", 1039 | ':flag_gn:' => "\u{1f1ec}\u{1f1f3}", 1040 | ':flag_gp:' => "\u{1f1ec}\u{1f1f5}", 1041 | ':flag_gq:' => "\u{1f1ec}\u{1f1f6}", 1042 | ':flag_gr:' => "\u{1f1ec}\u{1f1f7}", 1043 | ':flag_gs:' => "\u{1f1ec}\u{1f1f8}", 1044 | ':flag_gt:' => "\u{1f1ec}\u{1f1f9}", 1045 | ':flag_gu:' => "\u{1f1ec}\u{1f1fa}", 1046 | ':flag_gw:' => "\u{1f1ec}\u{1f1fc}", 1047 | ':flag_gy:' => "\u{1f1ec}\u{1f1fe}", 1048 | ':flag_hk:' => "\u{1f1ed}\u{1f1f0}", 1049 | ':flag_hm:' => "\u{1f1ed}\u{1f1f2}", 1050 | ':flag_hn:' => "\u{1f1ed}\u{1f1f3}", 1051 | ':flag_hr:' => "\u{1f1ed}\u{1f1f7}", 1052 | ':flag_ht:' => "\u{1f1ed}\u{1f1f9}", 1053 | ':flag_hu:' => "\u{1f1ed}\u{1f1fa}", 1054 | ':flag_id:' => "\u{1f1ee}\u{1f1e9}", 1055 | ':flag_ie:' => "\u{1f1ee}\u{1f1ea}", 1056 | ':flag_il:' => "\u{1f1ee}\u{1f1f1}", 1057 | ':flag_im:' => "\u{1f1ee}\u{1f1f2}", 1058 | ':flag_in:' => "\u{1f1ee}\u{1f1f3}", 1059 | ':flag_io:' => "\u{1f1ee}\u{1f1f4}", 1060 | ':flag_iq:' => "\u{1f1ee}\u{1f1f6}", 1061 | ':flag_ir:' => "\u{1f1ee}\u{1f1f7}", 1062 | ':flag_is:' => "\u{1f1ee}\u{1f1f8}", 1063 | ':flag_it:' => "\u{1f1ee}\u{1f1f9}", 1064 | ':flag_je:' => "\u{1f1ef}\u{1f1ea}", 1065 | ':flag_jm:' => "\u{1f1ef}\u{1f1f2}", 1066 | ':flag_jo:' => "\u{1f1ef}\u{1f1f4}", 1067 | ':flag_jp:' => "\u{1f1ef}\u{1f1f5}", 1068 | ':flag_ke:' => "\u{1f1f0}\u{1f1ea}", 1069 | ':flag_kg:' => "\u{1f1f0}\u{1f1ec}", 1070 | ':flag_kh:' => "\u{1f1f0}\u{1f1ed}", 1071 | ':flag_ki:' => "\u{1f1f0}\u{1f1ee}", 1072 | ':flag_km:' => "\u{1f1f0}\u{1f1f2}", 1073 | ':flag_kn:' => "\u{1f1f0}\u{1f1f3}", 1074 | ':flag_kp:' => "\u{1f1f0}\u{1f1f5}", 1075 | ':flag_kr:' => "\u{1f1f0}\u{1f1f7}", 1076 | ':flag_kw:' => "\u{1f1f0}\u{1f1fc}", 1077 | ':flag_ky:' => "\u{1f1f0}\u{1f1fe}", 1078 | ':flag_kz:' => "\u{1f1f0}\u{1f1ff}", 1079 | ':flag_la:' => "\u{1f1f1}\u{1f1e6}", 1080 | ':flag_lb:' => "\u{1f1f1}\u{1f1e7}", 1081 | ':flag_lc:' => "\u{1f1f1}\u{1f1e8}", 1082 | ':flag_li:' => "\u{1f1f1}\u{1f1ee}", 1083 | ':flag_lk:' => "\u{1f1f1}\u{1f1f0}", 1084 | ':flag_lr:' => "\u{1f1f1}\u{1f1f7}", 1085 | ':flag_ls:' => "\u{1f1f1}\u{1f1f8}", 1086 | ':flag_lt:' => "\u{1f1f1}\u{1f1f9}", 1087 | ':flag_lu:' => "\u{1f1f1}\u{1f1fa}", 1088 | ':flag_lv:' => "\u{1f1f1}\u{1f1fb}", 1089 | ':flag_ly:' => "\u{1f1f1}\u{1f1fe}", 1090 | ':flag_ma:' => "\u{1f1f2}\u{1f1e6}", 1091 | ':flag_mc:' => "\u{1f1f2}\u{1f1e8}", 1092 | ':flag_md:' => "\u{1f1f2}\u{1f1e9}", 1093 | ':flag_me:' => "\u{1f1f2}\u{1f1ea}", 1094 | ':flag_mf:' => "\u{1f1f2}\u{1f1eb}", 1095 | ':flag_mg:' => "\u{1f1f2}\u{1f1ec}", 1096 | ':flag_mh:' => "\u{1f1f2}\u{1f1ed}", 1097 | ':flag_mk:' => "\u{1f1f2}\u{1f1f0}", 1098 | ':flag_ml:' => "\u{1f1f2}\u{1f1f1}", 1099 | ':flag_mm:' => "\u{1f1f2}\u{1f1f2}", 1100 | ':flag_mn:' => "\u{1f1f2}\u{1f1f3}", 1101 | ':flag_mo:' => "\u{1f1f2}\u{1f1f4}", 1102 | ':flag_mp:' => "\u{1f1f2}\u{1f1f5}", 1103 | ':flag_mq:' => "\u{1f1f2}\u{1f1f6}", 1104 | ':flag_mr:' => "\u{1f1f2}\u{1f1f7}", 1105 | ':flag_ms:' => "\u{1f1f2}\u{1f1f8}", 1106 | ':flag_mt:' => "\u{1f1f2}\u{1f1f9}", 1107 | ':flag_mu:' => "\u{1f1f2}\u{1f1fa}", 1108 | ':flag_mv:' => "\u{1f1f2}\u{1f1fb}", 1109 | ':flag_mw:' => "\u{1f1f2}\u{1f1fc}", 1110 | ':flag_mx:' => "\u{1f1f2}\u{1f1fd}", 1111 | ':flag_my:' => "\u{1f1f2}\u{1f1fe}", 1112 | ':flag_mz:' => "\u{1f1f2}\u{1f1ff}", 1113 | ':flag_na:' => "\u{1f1f3}\u{1f1e6}", 1114 | ':flag_nc:' => "\u{1f1f3}\u{1f1e8}", 1115 | ':flag_ne:' => "\u{1f1f3}\u{1f1ea}", 1116 | ':flag_nf:' => "\u{1f1f3}\u{1f1eb}", 1117 | ':flag_ng:' => "\u{1f1f3}\u{1f1ec}", 1118 | ':flag_ni:' => "\u{1f1f3}\u{1f1ee}", 1119 | ':flag_nl:' => "\u{1f1f3}\u{1f1f1}", 1120 | ':flag_no:' => "\u{1f1f3}\u{1f1f4}", 1121 | ':flag_np:' => "\u{1f1f3}\u{1f1f5}", 1122 | ':flag_nr:' => "\u{1f1f3}\u{1f1f7}", 1123 | ':flag_nu:' => "\u{1f1f3}\u{1f1fa}", 1124 | ':flag_nz:' => "\u{1f1f3}\u{1f1ff}", 1125 | ':flag_om:' => "\u{1f1f4}\u{1f1f2}", 1126 | ':flag_pa:' => "\u{1f1f5}\u{1f1e6}", 1127 | ':flag_pe:' => "\u{1f1f5}\u{1f1ea}", 1128 | ':flag_pf:' => "\u{1f1f5}\u{1f1eb}", 1129 | ':flag_pg:' => "\u{1f1f5}\u{1f1ec}", 1130 | ':flag_ph:' => "\u{1f1f5}\u{1f1ed}", 1131 | ':flag_pk:' => "\u{1f1f5}\u{1f1f0}", 1132 | ':flag_pl:' => "\u{1f1f5}\u{1f1f1}", 1133 | ':flag_pm:' => "\u{1f1f5}\u{1f1f2}", 1134 | ':flag_pn:' => "\u{1f1f5}\u{1f1f3}", 1135 | ':flag_pr:' => "\u{1f1f5}\u{1f1f7}", 1136 | ':flag_ps:' => "\u{1f1f5}\u{1f1f8}", 1137 | ':flag_pt:' => "\u{1f1f5}\u{1f1f9}", 1138 | ':flag_pw:' => "\u{1f1f5}\u{1f1fc}", 1139 | ':flag_py:' => "\u{1f1f5}\u{1f1fe}", 1140 | ':flag_qa:' => "\u{1f1f6}\u{1f1e6}", 1141 | ':flag_re:' => "\u{1f1f7}\u{1f1ea}", 1142 | ':flag_ro:' => "\u{1f1f7}\u{1f1f4}", 1143 | ':flag_rs:' => "\u{1f1f7}\u{1f1f8}", 1144 | ':flag_ru:' => "\u{1f1f7}\u{1f1fa}", 1145 | ':flag_rw:' => "\u{1f1f7}\u{1f1fc}", 1146 | ':flag_sa:' => "\u{1f1f8}\u{1f1e6}", 1147 | ':flag_sb:' => "\u{1f1f8}\u{1f1e7}", 1148 | ':flag_sc:' => "\u{1f1f8}\u{1f1e8}", 1149 | ':flag_sd:' => "\u{1f1f8}\u{1f1e9}", 1150 | ':flag_se:' => "\u{1f1f8}\u{1f1ea}", 1151 | ':flag_sg:' => "\u{1f1f8}\u{1f1ec}", 1152 | ':flag_sh:' => "\u{1f1f8}\u{1f1ed}", 1153 | ':flag_si:' => "\u{1f1f8}\u{1f1ee}", 1154 | ':flag_sj:' => "\u{1f1f8}\u{1f1ef}", 1155 | ':flag_sk:' => "\u{1f1f8}\u{1f1f0}", 1156 | ':flag_sl:' => "\u{1f1f8}\u{1f1f1}", 1157 | ':flag_sm:' => "\u{1f1f8}\u{1f1f2}", 1158 | ':flag_sn:' => "\u{1f1f8}\u{1f1f3}", 1159 | ':flag_so:' => "\u{1f1f8}\u{1f1f4}", 1160 | ':flag_sr:' => "\u{1f1f8}\u{1f1f7}", 1161 | ':flag_ss:' => "\u{1f1f8}\u{1f1f8}", 1162 | ':flag_st:' => "\u{1f1f8}\u{1f1f9}", 1163 | ':flag_sv:' => "\u{1f1f8}\u{1f1fb}", 1164 | ':flag_sx:' => "\u{1f1f8}\u{1f1fd}", 1165 | ':flag_sy:' => "\u{1f1f8}\u{1f1fe}", 1166 | ':flag_sz:' => "\u{1f1f8}\u{1f1ff}", 1167 | ':flag_tc:' => "\u{1f1f9}\u{1f1e8}", 1168 | ':flag_td:' => "\u{1f1f9}\u{1f1e9}", 1169 | ':flag_tf:' => "\u{1f1f9}\u{1f1eb}", 1170 | ':flag_tg:' => "\u{1f1f9}\u{1f1ec}", 1171 | ':flag_th:' => "\u{1f1f9}\u{1f1ed}", 1172 | ':flag_tj:' => "\u{1f1f9}\u{1f1ef}", 1173 | ':flag_tk:' => "\u{1f1f9}\u{1f1f0}", 1174 | ':flag_tl:' => "\u{1f1f9}\u{1f1f1}", 1175 | ':flag_tm:' => "\u{1f1f9}\u{1f1f2}", 1176 | ':flag_tn:' => "\u{1f1f9}\u{1f1f3}", 1177 | ':flag_to:' => "\u{1f1f9}\u{1f1f4}", 1178 | ':flag_tr:' => "\u{1f1f9}\u{1f1f7}", 1179 | ':flag_tt:' => "\u{1f1f9}\u{1f1f9}", 1180 | ':flag_tv:' => "\u{1f1f9}\u{1f1fb}", 1181 | ':flag_tw:' => "\u{1f1f9}\u{1f1fc}", 1182 | ':flag_tz:' => "\u{1f1f9}\u{1f1ff}", 1183 | ':flag_ua:' => "\u{1f1fa}\u{1f1e6}", 1184 | ':flag_ug:' => "\u{1f1fa}\u{1f1ec}", 1185 | ':flag_um:' => "\u{1f1fa}\u{1f1f2}", 1186 | ':flag_us:' => "\u{1f1fa}\u{1f1f8}", 1187 | ':flag_uy:' => "\u{1f1fa}\u{1f1fe}", 1188 | ':flag_uz:' => "\u{1f1fa}\u{1f1ff}", 1189 | ':flag_va:' => "\u{1f1fb}\u{1f1e6}", 1190 | ':flag_vc:' => "\u{1f1fb}\u{1f1e8}", 1191 | ':flag_ve:' => "\u{1f1fb}\u{1f1ea}", 1192 | ':flag_vg:' => "\u{1f1fb}\u{1f1ec}", 1193 | ':flag_vi:' => "\u{1f1fb}\u{1f1ee}", 1194 | ':flag_vn:' => "\u{1f1fb}\u{1f1f3}", 1195 | ':flag_vu:' => "\u{1f1fb}\u{1f1fa}", 1196 | ':flag_wf:' => "\u{1f1fc}\u{1f1eb}", 1197 | ':flag_ws:' => "\u{1f1fc}\u{1f1f8}", 1198 | ':flag_ye:' => "\u{1f1fe}\u{1f1ea}", 1199 | ':flag_yt:' => "\u{1f1fe}\u{1f1f9}", 1200 | ':flag_za:' => "\u{1f1ff}\u{1f1e6}", 1201 | ':flag_zm:' => "\u{1f1ff}\u{1f1f2}", 1202 | ':flag_zw:' => "\u{1f1ff}\u{1f1fc}", 1203 | 1204 | // Telegram Desktop 1205 | '<3' => "\u{2764}", 1206 | 'xD' => "\u{1f606}", 1207 | ':like:' => "\u{1f44d}", 1208 | ':dislike:' => "\u{1f44e}", 1209 | ':-*' => "\u{1f618}", // Kiss heart 1210 | ':-)' => "\u{1f60a}", // Blush 1211 | '8-)' => "\u{1f60d}", // Heart eyes 1212 | 'B-)' => "\u{1f192}", // Cool 1213 | ':-D' => "\u{1f603}", // Smiley 1214 | ';-)' => "\u{1f609}", // Wink 1215 | ';-P' => "\u{1f61c}", // Tongue wink 1216 | ':-p' => "\u{1f60b}", // Yum 1217 | '3(' => "\u{1f614}", // Pensive 1218 | ':-(' => "\u{1f61e}", // Disappointed 1219 | ':]' => "\u{1f60f}", // Smirk 1220 | ':\'(' => "\u{1f622}", // Cry 1221 | ':_(' => "\u{1f62d}", // Sob 1222 | ':((' => "\u{1f629}", // Weary 1223 | ':o' => "\u{1f628}", // Fearful 1224 | ':|' => "\u{1f610}", // Neutral face 1225 | '3-)' => "\u{1f60c}", // Relieved 1226 | // '>(' => "\u{1f620}", // Angry 1227 | // '>((' => "\u{1f621}", // Rage 1228 | 'O:)' => "\u{1f607}", // Innocent 1229 | ';o' => "\u{1f630}", // Cold sweat 1230 | '8|' => "\u{1f633}", // Flushed 1231 | '8o' => "\u{1f632}", // Astonished 1232 | ':X' => "\u{1f637}", // Mask 1233 | '}:)' => "\u{1f608}", // Smiling Imp 1234 | 1235 | // Custom 1236 | ':>' => "\u{1f603}", // Smiley 1237 | ']:D' => "\u{1f603}", // Smiley 1238 | '^3^' => "\u{1f619}", // Kissing face with smiling eyes 1239 | ':lol:' => "\u{1f602}", // Joy 1240 | ':\'D' => "\u{1f602}", // Joy 1241 | // '>X' => "\u{1f635}", // Dizzy 1242 | ':die:' => "\u{1f635}", // Dizzy 1243 | ':sun:' => "\u{2600}", 1244 | 1245 | // Emoji v5.0 TEMP-NAME 1246 | ':star-struck:' => "\u{1f929}", 1247 | ':starry-eyed:' => "\u{1f929}", 1248 | // ------ 1249 | ':distrust:' => "\u{1f928}", 1250 | ':skeptic:' => "\u{1f928}", 1251 | ':scepticism:' => "\u{1f928}", 1252 | ':disapproval:' => "\u{1f928}", 1253 | ':disbelief:' => "\u{1f928}", 1254 | // ------ 1255 | ':goofy:' => "\u{1f92a}", 1256 | ':zany-face:' => "\u{1f92a}", 1257 | // ------ 1258 | ':swearing:' => "\u{1f92c}", 1259 | ':cursing:' => "\u{1f92c}", 1260 | // ------ 1261 | ':shush:' => "\u{1f92b}", 1262 | ':shushing-face:' => "\u{1f92b}", 1263 | // ------ 1264 | ':whoops:' => "\u{1f92d}", 1265 | // ------ 1266 | ':stuffy:' => "\u{1f9d0}", 1267 | ':wealthy:' => "\u{1f9d0}", 1268 | // ------ 1269 | ':brain:' => "\u{1f9e0}", 1270 | ':scarf:' => "\u{1f9e3}", 1271 | ':gloves:' => "\u{1f9e4}", 1272 | ':coat:' => "\u{1f9e5}", 1273 | ':baseball_cap:' => "\u{1f9e2}", 1274 | ':socks:' => "\u{1f9e6}", 1275 | // ------ 1276 | ':zebra:' => "\u{1f993}", 1277 | ':giraffe:' => "\u{1f992}", 1278 | ':hedgehog:' => "\u{1f994}", 1279 | ':sauropod:' => "\u{1f995}", 1280 | ':trex:' => "\u{1f996}", 1281 | ':cricket:' => "\u{1f997}", 1282 | ':coconut:' => "\u{1f965}", 1283 | ':broccoli:' => "\u{1f966}", 1284 | ':pretzel:' => "\u{1f968}", 1285 | ':steak:' => "\u{1f969}", 1286 | ':sandwich:' => "\u{1f96a}", 1287 | ':bowl:' => "\u{1f963}", 1288 | ':canned_food:' => "\u{1f96b}", 1289 | ':pie:' => "\u{1f967}", 1290 | ':chopsticks:' => "\u{1f962}", 1291 | ':sled:' => "\u{1f6f7}", 1292 | ':curling:' => "\u{1f94c}", 1293 | 1294 | ':orange:' => "\u{1f34a}", // Tangerine 1295 | ':apple-red:' => "\u{1f34e}", 1296 | ':birthcake:' => "\u{1f382}", // Birthday 1297 | 1298 | '[1]' => "1\u{20e3}", 1299 | '[2]' => "2\u{20e3}", 1300 | '[3]' => "3\u{20e3}", 1301 | '[4]' => "4\u{20e3}", 1302 | '[5]' => "5\u{20e3}", 1303 | '[6]' => "6\u{20e3}", 1304 | '[7]' => "7\u{20e3}", 1305 | '[8]' => "8\u{20e3}", 1306 | '[9]' => "9\u{20e3}", 1307 | '[0]' => "0\u{20e3}", 1308 | 1309 | ':medal-1:' => "\u{1f947}", 1310 | ':medal-2:' => "\u{1f948}", 1311 | ':medal-3:' => "\u{1f949}", 1312 | ':bronce:' => "\u{1f947}", 1313 | ':bronze:' => "\u{1f947}", 1314 | ':silver:' => "\u{1f948}", 1315 | ':golden:' => "\u{1f949}", 1316 | 1317 | ':medal-gold:' => "\u{1f3c5}", // Sports medal 1318 | ':medal-star:' => "\u{1f396}", // Militar medal 1319 | ':medal-sports:' => "\u{1f3c5}", 1320 | ':medal-militar:' => "\u{1f396}", 1321 | 1322 | ':check:' => "\u{2705}", 1323 | ':times:' => "\u{274c}", 1324 | ':clock:' => "\u{1f551}", // Clock 2 1325 | ':world:' => "\u{1f30d}", // Europe 1326 | ':world-europe:' => "\u{1f30d}", 1327 | ':world-usa:' => "\u{1f30e}", 1328 | ':world-asia:' => "\u{1f30f}", 1329 | 1330 | ':love:' => "\u{2764}", 1331 | ':red_heart:' => "\u{2764}", 1332 | ':heart-red:' => "\u{2764}", 1333 | ':heart-blue:' => "\u{1f499}", 1334 | ':heart-green:' => "\u{1f49a}", 1335 | ':heart-yellow:' => "\u{1f49b}", 1336 | ':heart-purple:' => "\u{1f49c}", 1337 | ':heart-black:' => "\u{1f5a4}", 1338 | 1339 | ); ?> 1340 | -------------------------------------------------------------------------------- /src/Keyboards/InlineKeyboard.php: -------------------------------------------------------------------------------- 1 | parent = $parent; 12 | } 13 | 14 | function row($array = NULL){ 15 | if(!is_array($array)){ return new InlineKeyboardRow($this, $this->parent->bot); } 16 | // ------ 17 | $row = new InlineKeyboardRow($this, $this->parent->bot); 18 | foreach($array as $but){ 19 | $text = $but; 20 | $request = $but; 21 | $switch = NULL; 22 | if(is_array($but)){ 23 | if(isset($but['text'])){ $text = $but['text']; } 24 | elseif(isset($but[0])){ $text = $but[0]; } 25 | 26 | if(isset($but['request'])){ $request = $but['request']; } 27 | elseif(isset($but[1])){ $request = $but[1]; } 28 | 29 | if(isset($but['switch'])){ $switch = $but['switch']; } 30 | elseif(isset($but[2])){ $switch = $but[2]; } 31 | } 32 | $row->button($text, $request, $switch); 33 | } 34 | $row->end_row(); 35 | return $this; 36 | } 37 | 38 | function row_button($text, $request = NULL, $switch = NULL){ 39 | return $this->row() 40 | ->button($text, $request, $switch) 41 | ->end_row(); 42 | } 43 | 44 | function push($data){ 45 | if(!is_array($data)){ return FALSE; } 46 | $this->rows[] = $data; 47 | return $this; 48 | } 49 | 50 | function show(){ 51 | $this->parent->_push('reply_markup', [ 52 | 'inline_keyboard' => $this->rows, 53 | ]); 54 | $this->_reset(); 55 | return $this->parent; 56 | } 57 | 58 | function _reset(){ 59 | $this->rows = array(); 60 | return $this; 61 | } 62 | } 63 | 64 | class InlineKeyboardRow { 65 | private $buttons; 66 | private $parent; 67 | private $bot; 68 | 69 | function __construct($parent, $bot = NULL){ 70 | $this->parent = $parent; 71 | if(!empty($bot)){ $this->bot = $bot; } 72 | } 73 | 74 | function button($text, $request = NULL, $switch = NULL){ 75 | $data = array(); 76 | if($this->parent->convert_emoji){ /* TODO */ } 77 | $data['text'] = $text; 78 | if(filter_var($request, FILTER_VALIDATE_URL) !== FALSE){ $data['url'] = $request; } 79 | elseif($switch === TRUE or (is_string($switch) && strtolower($switch) == "command")){ 80 | // Iniciar por privado 81 | $request = preg_replace("/([^-_a-zA-Z0-9]+)/i", "", $request); // Caracteres permitidos 82 | $data['url'] = "https://t.me/" .$this->bot->username ."?start=" .$request; 83 | }elseif(is_string($switch) && strtolower($switch) == "share"){ 84 | $enc = NULL; 85 | if(is_array($request) && count($request) == 2){ 86 | $enc = ['url' => urlencode($request[0]), 'text' => urldecode($request[1])]; 87 | }else{ 88 | $enc = ['url' => urlencode($request)]; 89 | } 90 | $data['url'] = "https://t.me/share/url?" .http_build_query($enc); 91 | }elseif(strtolower($switch) == "text"){ 92 | $data['switch_inline_query'] = $switch; 93 | $data['callback_data'] = "T:" .$request; 94 | }elseif(strtolower($switch) == "pay"){ 95 | $data['switch_inline_query'] = $switch; 96 | $data['pay'] = TRUE; 97 | }elseif($switch === FALSE){ 98 | $data['switch_inline_query'] = $request; 99 | }else{ 100 | $data['switch_inline_query'] = $switch; 101 | $data['callback_data'] = $request; 102 | } 103 | $this->buttons[] = $data; 104 | return $this; 105 | } 106 | function end_row(){ 107 | $this->parent->push($this->buttons); 108 | return $this->parent; 109 | } 110 | } 111 | 112 | ?> 113 | -------------------------------------------------------------------------------- /src/Keyboards/Keyboard.php: -------------------------------------------------------------------------------- 1 | selective(FALSE); 12 | $this->parent = $parent; 13 | } 14 | 15 | function row($array = NULL){ 16 | if(!is_array($array)){ return new KeyboardRow($this); } 17 | // ------- 18 | $row = new KeyboardRow($this); 19 | foreach($array as $v){ 20 | $row->button($v); 21 | } 22 | $row->end_row(); 23 | return $this; 24 | } 25 | 26 | function row_button($text, $request = NULL){ 27 | return $this->row() 28 | ->button($text, $request) 29 | ->end_row(); 30 | } 31 | 32 | function push($data){ 33 | if(!is_array($data)){ return FALSE; } 34 | $this->rows[] = $data; 35 | return $this; 36 | } 37 | 38 | function selective($val = TRUE){ 39 | $this->config['selective'] = $val; 40 | return $this; 41 | } 42 | 43 | function show($one_time = FALSE, $resize = FALSE){ 44 | $this->parent->_push('reply_markup', [ 45 | 'keyboard' => $this->rows, 46 | 'resize_keyboard' => $resize, 47 | 'one_time_keyboard' => $one_time, 48 | 'selective' => $this->config['selective'] 49 | ]); 50 | $this->_reset(); 51 | return $this->parent; 52 | } 53 | 54 | function hide($sel = FALSE){ 55 | if($sel === TRUE){ $this->selective(TRUE); } 56 | $this->parent->_push('reply_markup', [ 57 | 'hide_keyboard' => TRUE, 58 | 'selective' => $this->config['selective'] 59 | ]); 60 | $this->_reset(); 61 | return $this->parent; 62 | } 63 | 64 | function _reset(){ 65 | $this->rows = array(); 66 | return $this; 67 | } 68 | } 69 | 70 | class KeyboardRow { 71 | private $buttons; 72 | private $parent; 73 | 74 | function __construct($parent){ 75 | $this->parent = $parent; 76 | } 77 | 78 | function button($text, $request = NULL){ 79 | $data = array(); 80 | if($this->parent->convert_emoji){ /* TODO */ } 81 | $data['text'] = $text; 82 | if($request === TRUE or $request == "contact"){ $data['request_contact'] = TRUE; } 83 | elseif($request === FALSE or $request == "location"){ $data['request_location'] = TRUE; } 84 | $this->buttons[] = $data; 85 | return $this; 86 | } 87 | function end_row(){ 88 | $this->parent->push($this->buttons); 89 | return $this->parent; 90 | } 91 | } 92 | 93 | ?> 94 | -------------------------------------------------------------------------------- /src/Message.php: -------------------------------------------------------------------------------- 1 | 51 | -------------------------------------------------------------------------------- /src/Payments/Stripe.php: -------------------------------------------------------------------------------- 1 | parent = $parent; 11 | $this 12 | ->currency("EUR") 13 | ->payload(time() . mt_rand(1000, 9999)); 14 | } 15 | 16 | function title($name, $description = NULL){ 17 | $this->config['title'] = $name; 18 | if(!empty($description)){ return $this->description($description); } 19 | return $this; 20 | } 21 | 22 | function description($text){ 23 | $this->config['description'] = $text; 24 | return $this; 25 | } 26 | 27 | function token($token, $payload = NULL, $start = NULL){ 28 | $this->config['provider_token'] = $token; 29 | if(!empty($payload)){ $this->payload($payload); } 30 | if(!empty($start)){ $this->start($start); } 31 | return $this; 32 | } 33 | 34 | function payload($data){ 35 | $this->config['payload'] = $data; 36 | return $this; 37 | } 38 | 39 | function start($data){ 40 | $this->config['start_parameter'] = $data; 41 | return $this; 42 | } 43 | 44 | function currency($data){ 45 | $this->config['currency'] = $data; 46 | return $this; 47 | } 48 | 49 | function price($label, $amount = NULL){ 50 | if(is_array($label) and empty($amount)){ 51 | foreach($label as $l => $a){ $this->price($l, $a); } 52 | return $this; 53 | } 54 | 55 | if(is_float($amount)){ $amount = $amount * 100; } 56 | 57 | $this->config['prices'][] = [ 58 | "label" => $label, 59 | "amount" => $amount 60 | ]; 61 | 62 | return $this; 63 | } 64 | 65 | function flexible($value = TRUE){ 66 | $this->config['is_flexible'] = (bool) $value; 67 | return $this; 68 | } 69 | 70 | function request($data){ 71 | if(is_string($data)){ $data = [$data]; } 72 | elseif($data === TRUE){ $data = ['name', 'phone', 'email', 'shipping']; } 73 | foreach($data as $k){ 74 | if(in_array($k, ['name'])){ $this->request_name(TRUE); } 75 | elseif(in_array($k, ['phone', 'number', 'phone_number', 'mobile'])){ $this->request_phone(TRUE); } 76 | elseif(in_array($k, ['email'])){ $this->request_email(TRUE); } 77 | elseif(in_array($k, ['shipping', 'address'])){ $this->request_shipping(TRUE); } 78 | } 79 | return $this; 80 | } 81 | 82 | function request_name($value = TRUE){ 83 | $this->config['need_name'] = (bool) $value; 84 | return $this; 85 | } 86 | 87 | function request_phone($value = TRUE){ 88 | $this->config['need_phone_number'] = (bool) $value; 89 | return $this; 90 | } 91 | 92 | function request_email($value = TRUE){ 93 | $this->config['need_email'] = (bool) $value; 94 | return $this; 95 | } 96 | 97 | function request_shipping($value = TRUE){ 98 | $this->config['need_shipping_address'] = (bool) $value; 99 | return $this; 100 | } 101 | 102 | function photo($url, $width = NULL, $height = NULL, $size = NULL){ 103 | if(!empty($width) and strpos($width, "x") !== FALSE){ 104 | $width = explode("x", $width); 105 | $height = $width[1]; 106 | $width = $width[0]; 107 | } 108 | 109 | if(filter_var($url, FILTER_VALIDATE_URL) !== FALSE){ return $this; } 110 | 111 | $this->config['photo_url'] = $url; 112 | if($width and $height){ 113 | $this->config['photo_width'] = $width; 114 | $this->config['photo_height'] = $height; 115 | } 116 | if($size){ 117 | $this->config['photo_size'] = $size; 118 | } 119 | 120 | return $this; 121 | } 122 | 123 | function show(){ 124 | foreach($this->config as $k => $v){ $this->parent->_push($k, $v); } 125 | $this->_reset(); 126 | return $this->parent; 127 | } 128 | 129 | function _reset(){ 130 | $this->config = array(); 131 | return $this; 132 | } 133 | } 134 | 135 | ?> 136 | -------------------------------------------------------------------------------- /src/Receiver.php: -------------------------------------------------------------------------------- 1 | user = new User(NULL); 9 | $this->chat = new Chat(NULL); 10 | 11 | $this->process(); 12 | if(!empty($uid)){ 13 | if($uid instanceof Bot){ 14 | $this->bot = $uid; 15 | }else{ 16 | $this->set_access($uid, $key, $name); 17 | } 18 | } 19 | $this->send = new Sender($this); 20 | } 21 | 22 | private $raw; 23 | private $data = array(); 24 | public $bot = array(); 25 | public $key = NULL; 26 | public $id = NULL; 27 | public $message = NULL; // DEPRECATED 28 | public $message_id = NULL; 29 | public $timestamp = 0; 30 | public $chat = NULL; 31 | public $user = NULL; 32 | public $language = NULL; 33 | public $entities = NULL; 34 | public $reply = NULL; 35 | public $new_user = NULL; 36 | public $new_users = array(); 37 | public $left_user = NULL; 38 | public $reply_user = NULL; 39 | public $forward_user = NULL; 40 | public $has_reply = FALSE; 41 | public $has_forward = FALSE; 42 | public $is_edit = FALSE; 43 | public $edit_date = NULL; 44 | public $reply_is_forward = FALSE; 45 | public $caption = NULL; 46 | public $offset = NULL; // inline query 47 | public $callback = FALSE; 48 | public $send = FALSE; // Class 49 | public $migrate_chat = NULL; 50 | public $input = NULL; // Text Regex Match 51 | public $author_signature = NULL; 52 | public $forward_signature = NULL; 53 | public $emojis = array(); 54 | 55 | private function set_access($uid, $key = NULL, $name = NULL){ 56 | $this->bot = new Bot($uid, $key, $name); 57 | 58 | // Set sender 59 | $this->send = new Sender($this->bot); 60 | return $this; 61 | } 62 | 63 | public function process($content = NULL){ 64 | if($content === NULL){ 65 | $content = file_get_contents("php://input"); 66 | } 67 | 68 | if(!empty($content)){ 69 | $this->raw = $content; 70 | $this->data = json_decode($content, TRUE); 71 | $this->id = $this->data['update_id']; 72 | if(isset($this->data['message']) or isset($this->data['edited_message'])){ 73 | $this->key = (isset($this->data['edited_message']) ? "edited_message" : "message"); 74 | if($this->key == "edited_message"){ 75 | $this->is_edit = TRUE; 76 | $this->edit_date = $this->data[$this->key]['edit_date']; 77 | } 78 | $this->message = $this->data[$this->key]['message_id']; // DEPRECATED 79 | $this->message_id = intval($this->data[$this->key]['message_id']); 80 | $this->timestamp = $this->data[$this->key]['date']; // HACK Tener en cuenta edit_date 81 | $this->chat = new Chat($this->data[$this->key]['chat']); 82 | $this->user = new User($this->data[$this->key]['from']); 83 | if(isset($this->data[$this->key]['from']['language_code'])){ 84 | $this->language = $this->data[$this->key]['from']['language_code']; 85 | if(strpos($this->language, "-") !== FALSE){ 86 | $this->language = explode("-", $this->language); 87 | $this->language = strtolower($this->language[0]); 88 | } 89 | } 90 | if(isset($this->data[$this->key]['caption'])){ 91 | $this->caption = $this->data[$this->key]['caption']; 92 | } 93 | if(isset($this->data[$this->key]['reply_to_message'])){ 94 | $this->has_reply = TRUE; 95 | $this->reply_user = new User($this->data[$this->key]['reply_to_message']['from']); 96 | $this->reply = (object) $this->data[$this->key]['reply_to_message']; 97 | $this->reply_is_forward = (isset($this->data[$this->key]['reply_to_message']['forward_from'])); 98 | if($this->reply_is_forward){ 99 | $this->reply->forward_from = new User($this->data[$this->key]['reply_to_message']['forward_from']); 100 | // No se puede hacer reply a un forward con otro forward, 101 | // por lo que no hay problema en hacer esto. 102 | $this->forward_user = new User($this->data[$this->key]['reply_to_message']['forward_from']); 103 | if(isset($this->data[$this->key]['reply_to_message']['forward_from_chat'])){ 104 | $this->reply->forward_from_chat = new Chat($this->data[$this->key]['reply_to_message']['forward_from_chat']); 105 | } 106 | $this->forward_signature = $this->data[$this->key]['reply_to_message']['forward_signature']; 107 | } 108 | } 109 | if(isset($this->data[$this->key]['forward_from']) or isset($this->data[$this->key]['forward_from_chat'])){ 110 | $this->has_forward = TRUE; 111 | if(isset($this->data[$this->key]['forward_from'])){ 112 | $this->forward_user = new User($this->data[$this->key]['forward_from']); 113 | } 114 | } 115 | if(isset($this->data[$this->key]['new_chat_members'])){ 116 | foreach($this->data[$this->key]['new_chat_members'] as $user){ 117 | $this->new_users[] = new User($user); 118 | } 119 | $this->new_user = $this->new_users[0]; // COMPATIBILITY: Tal y como hace Telegram, se agrega el primer usuario. 120 | // DEPRECTAED en un futuro? 121 | }elseif(isset($this->data[$this->key]['new_chat_member'])){ 122 | $this->new_user = new User($this->data[$this->key]['new_chat_member']); 123 | $this->new_users = [$this->new_user]; 124 | }elseif(isset($this->data[$this->key]['left_chat_member'])){ 125 | // DEPRECATED 126 | $this->new_user = new User($this->data[$this->key]['left_chat_member']); 127 | $this->left_user = $this->new_user; 128 | }elseif(isset($this->data[$this->key]['migrate_to_chat_id'])){ 129 | $this->migrate_chat = $this->data[$this->key]['migrate_to_chat_id']; 130 | }elseif(isset($this->data[$this->key]['migrate_from_chat_id'])){ 131 | $this->migrate_chat = $this->data[$this->key]['migrate_from_chat_id']; 132 | } 133 | if(isset($this->data[$this->key]['entities'])){ 134 | foreach($this->data[$this->key]['entities'] as $ent){ 135 | $this->entities[] = new Elements\MessageEntity($ent, $this->text()); 136 | } 137 | } 138 | }elseif(isset($this->data['callback_query'])){ 139 | $this->key = "callback_query"; 140 | $this->id = $this->data[$this->key]['id']; 141 | $this->message = $this->data[$this->key]['message']['message_id']; // DEPRECATED 142 | $this->message_id = $this->data[$this->key]['message']['message_id']; 143 | $this->chat = new Chat($this->data[$this->key]['message']['chat']); 144 | $this->user = new User($this->data[$this->key]['from']); 145 | $this->callback = $this->data[$this->key]['data']; 146 | }elseif(isset($this->data['channel_post']) or isset($this->data['edited_channel_post'])){ 147 | $this->key = (isset($this->data['edited_channel_post']) ? "edited_channel_post" : "channel_post"); 148 | if($this->key == "edited_channel_post"){ 149 | $this->is_edit = TRUE; 150 | $this->edit_date = $this->data[$this->key]['edit_date']; 151 | } 152 | $this->id = $this->data['update_id']; 153 | $this->message_id = $this->data[$this->key]['message_id']; 154 | $this->timestamp = $this->data[$this->key]['date']; 155 | $this->chat = (object) $this->data[$this->key]['chat']; 156 | 157 | if(isset($this->data[$this->key]['from'])){ 158 | $this->user = (object) $this->data[$this->key]['from']; 159 | } 160 | }elseif(isset($this->data['inline_query'])){ 161 | $this->key = "inline_query"; 162 | $this->id = $this->data[$this->key]['id']; 163 | // $this->message_id = $this->data[$this->key]['id']; 164 | $this->user = new User($this->data[$this->key]['from']); 165 | $this->chat = new Chat($this->data[$this->key]['from']); // Compatibility, but not set 166 | $this->offset = $this->data[$this->key]['offset']; 167 | } 168 | } 169 | } 170 | 171 | public function text_message(){ 172 | if($this->key == "callback_query"){ return $this->data[$this->key]['message']['text']; } 173 | elseif($this->has_reply){ return $this->data[$this->key]['reply_to_message']['text']; } 174 | return NULL; 175 | } 176 | 177 | public function text($clean = FALSE){ 178 | $text = @$this->data[$this->key]['text']; 179 | if($this->key == "callback_query"){ 180 | $text = @$this->data[$this->key]['data']; 181 | if(substr($text, 0, 2) != "T:"){ return NULL; } 182 | $text = substr($text, 2); 183 | } 184 | if($clean === TRUE){ $text = $this->clean('alphanumeric-full-spaces', $text); } 185 | return $text; 186 | } 187 | 188 | public function text_query(){ 189 | if($this->key != "inline_query"){ return FALSE; } 190 | $text = $this->data[$this->key]['query']; 191 | if(empty($text)){ $text = NULL; } 192 | return $text; 193 | } 194 | 195 | public function text_query_has($input, $next_word = NULL, $position = NULL){ 196 | $text = $this->text_query(); 197 | if(empty($text)){ return FALSE; } 198 | return $this->text_has($input, $next_word, $position, $text, TRUE); 199 | } 200 | 201 | public function text_encoded($clean_quotes = FALSE){ 202 | $t = json_encode($this->text(FALSE)); 203 | if($clean_quotes){ $t = substr($t, 1, -1); } 204 | return $t; 205 | } 206 | 207 | public function text_contains($input, $strpos = NULL){ 208 | if(!is_array($input)){ $input = array($input); } 209 | $text = strtolower($this->text()); 210 | $text = $this->text_cleanup_prepare($text, FALSE); 211 | foreach($input as $i){ 212 | $j = $this->text_cleanup_prepare($i, FALSE); 213 | if( 214 | ($strpos === NULL and strpos($text, strtolower($j)) !== FALSE) or // Buscar cualquier coincidencia 215 | ($strpos === TRUE and strpos($text, strtolower($j)) === 0) or // Buscar textualmente eso al principio 216 | ($strpos === FALSE and strpos($this->text(), $i) === 0) or // Buscar textualmente al principio + CASE sensitive 217 | ($strpos !== NULL and strpos($text, strtolower($j)) == $strpos) // Buscar por strpos 218 | ){ 219 | return TRUE; 220 | } 221 | } 222 | return FALSE; 223 | } 224 | 225 | private function text_cleanup_prepare($input, $tolower = TRUE){ 226 | if($tolower){ $input = strtolower($input); } 227 | $vocals = [ 228 | "á" => "a", "é" => "e", "í" => "i", "ó" => "o", "ú" => "u", 229 | "à" => "a", "è" => "e", "ì" => "i", "ò" => "o", "ù" => "u", 230 | "Á" => "A", "É" => "E", "Í" => "I", "Ó" => "O", "Ú" => "U", 231 | "À" => "A", "È" => "E", "Ì" => "I", "Ò" => "O", "Ù" => "U" 232 | ]; 233 | $input = str_replace(array_keys($vocals), array_values($vocals), $input); 234 | $input = str_replace("%20", " ", $input); // HACK web 235 | if($tolower){ $input = strtolower($input); } 236 | return $input; 237 | } 238 | 239 | public function text_has($input, $next_word = NULL, $position = NULL, $text = NULL, $cleanup = TRUE){ 240 | // A diferencia de text_contains, esto no será valido si la palabra no es la misma. 241 | // ($input = "fanta") -> fanta OK , fanta! OK , fantasma KO 242 | if(!is_array($input)){ $input = array($input); } 243 | if(empty($input)){ return FALSE; } 244 | // FIXME si algun input contiene un PIPE | , ya me ha jodio. Controlarlo. 245 | 246 | $input = implode("|", $input); 247 | $input = $this->text_cleanup_prepare($input, TRUE); 248 | $input = str_replace("/", "\/", $input); // CHANGED fix para escapar comandos y demás. 249 | 250 | if(is_bool($next_word)){ $position = $next_word; $next_word = NULL; } 251 | elseif($next_word !== NULL){ 252 | if(!is_array($next_word)){ $next_word = array($next_word); } 253 | $next_word = implode("|", $next_word); 254 | $next_word = $this->text_cleanup_prepare($next_word, TRUE); 255 | $next_word = str_replace("/", "\/", $next_word); // CHANGED 256 | } 257 | 258 | // Al principio de frase 259 | if($position === TRUE){ 260 | if($next_word === NULL){ $regex = "^(" .$input .')([\s!.,"]?)'; } 261 | else{ $regex = "^(" .$input .')([\s!.,"]?)\s(' .$next_word .')([\s!?.,"]?)'; } 262 | // Al final de frase 263 | }elseif($position === FALSE){ 264 | if($next_word === NULL){ $regex = "(" .$input .')([!?,."]?)$'; } 265 | else{ $regex = "(" .$input .')([\s!.,"]?)\s(' .$next_word .')([?!.,"]?)$'; } 266 | // En cualquier posición 267 | }else{ 268 | if($next_word === NULL){ $regex = "(" .$input .')([\s!?.,"])|(' .$input .')$'; } 269 | else{ $regex = "(" .$input .')([\s!.,"]?)\s(' .$next_word .')([\s!?.,"])|(' .$input .')([\s!.,"]?)\s(' .$next_word .')([!?.,"]?)$'; } 270 | } 271 | 272 | if($text === NULL){ $text = strtolower($this->text()); } 273 | if($cleanup){ 274 | $text = $this->text_cleanup_prepare($text, FALSE); 275 | $text = strtolower($text); 276 | } 277 | return preg_match("/$regex/", $text); 278 | } 279 | 280 | // WIP TODO 281 | public function text_has_emoji($emoji = NULL, $return = FALSE){ 282 | if(empty($emoji)){ 283 | return (strpos($this->text_encoded(), '\u') !== FALSE); 284 | }elseif(is_array($emoji)){ 285 | foreach($emoji as $e){ 286 | if(empty($e)){ continue; } 287 | $r = $this->text_has_emoji($e, $return); 288 | if($r !== FALSE){ return $r; } 289 | } 290 | return FALSE; 291 | } 292 | if(in_array(substr($emoji, 0, 1), [':', '\\'])){ $emoji = $this->emoji($emoji); } 293 | $text = $this->text(); 294 | return (strpos($text, $emoji) !== FALSE); 295 | } 296 | 297 | public function text_regex($expr, $cleanup = TRUE){ 298 | if(!is_array($expr)){ 299 | if(empty(trim($expr))){ return FALSE; } 300 | $expr = [$expr]; 301 | } 302 | $text = $this->text(); 303 | if($cleanup){ $text = $this->text_cleanup_prepare($text, FALSE); } 304 | $repls = [ 305 | '/\{N:(\w+)\}/i' => '(?P<$1>[\\d]+)', 306 | '/\{S:(\w+)\}/i' => '(?P<$1>[\\w\\s?]+)', 307 | '/\{SL:(.+):(\w+)\}/i' => '(?P<$2>[\\w\\s?]+)$1', 308 | '/\{(\w+)\}/i' => '(?P<$1>[^\\s]+)', 309 | ]; 310 | 311 | foreach($expr as $ex){ 312 | $ex = preg_replace(array_keys($repls), array_values($repls), $ex); 313 | $r = preg_match_all("/$ex/i", $text, $matches); 314 | if($r){ 315 | foreach($matches as $k => $v){ 316 | if(is_numeric($k) and $k != 0){ 317 | unset($matches[$k]); 318 | continue; 319 | } 320 | $matches[$k] = current($v); // Get value, not array 321 | } 322 | $this->input = (object) $matches; 323 | return $r; 324 | } 325 | } 326 | return FALSE; 327 | } 328 | 329 | public function text_mention($user = NULL){ 330 | // Incluye users registrados y anónimos. 331 | // NULL -> decir si hay usuarios mencionados o no (T/F) 332 | // TRUE -> array [ID => @nombre o nombre] 333 | // NUM -> decir si el NUM ID usuario está mencionado o no, y si es @nombre, parsear para validar NUM ID. 334 | // STR -> decir si nombre o @nombre está mencionado o no. 335 | if(empty($this->entities)){ return FALSE; } 336 | $users = array(); 337 | $text = $this->text(FALSE); // No UTF-8 clean 338 | foreach($this->entities as $e){ 339 | if($e->type == 'text_mention'){ 340 | $users[] = [$e->user->id => $e->value]; 341 | }elseif($e->type == 'mention'){ 342 | $u = trim($e->value); // @username 343 | // $d = $this->send->get_member_info($u); HACK 344 | $d = FALSE; 345 | $users[] = ($d === FALSE ? $u : [$d['user']['id'] => $u] ); 346 | } 347 | } 348 | if($user == NULL){ return (count($users) > 0 ? $users[0] : FALSE); } 349 | if($user === TRUE){ return $users; } 350 | if(is_numeric($user)){ 351 | if($user < count($users)){ 352 | $k = array_keys($users); 353 | $v = array_values($users); 354 | return [ $k[$user] => $v[$user] ]; 355 | } 356 | return in_array($user, array_keys($users)); 357 | } 358 | if(is_string($user)){ return in_array($user, array_values($users)); } 359 | return FALSE; 360 | } 361 | 362 | public function text_email($email = NULL){ 363 | // NULL -> saca el primer mail o FALSE. 364 | // TRUE -> array [emails] 365 | // STR -> email definido. 366 | if(empty($this->entities)){ return FALSE; } 367 | $emails = array(); 368 | $text = $this->text(FALSE); // No UTF-8 clean 369 | foreach($this->entities as $e){ 370 | if($e->type == 'email'){ $emails[] = strtolower($e->value); } 371 | } 372 | if($email == NULL){ return (count($emails) > 0 ? $emails[0] : FALSE); } 373 | if($email === TRUE){ return $emails; } 374 | if(is_string($email)){ return in_array(strtolower($email), $emails); } 375 | return FALSE; 376 | } 377 | 378 | public function text_command($cmd = NULL, $begin = TRUE){ 379 | // NULL -> saca el primer comando o FALSE. 380 | // TRUE -> array [comandos] 381 | // STR -> comando definido. 382 | // $begin -> si es comando inicial 383 | // $begin STR -> si es comando con ese parametro 384 | if(empty($this->entities)){ return FALSE; } 385 | if($cmd === FALSE){ $begin = FALSE; $cmd = NULL; } 386 | $cmds = array(); 387 | $initbegin = FALSE; 388 | foreach($this->entities as $e){ 389 | if($e->type == 'bot_command'){ 390 | $cmds[] = strtolower($e->value); 391 | if($initbegin == FALSE && $e->offset == 0){ $initbegin = TRUE; } 392 | } 393 | } 394 | if($cmd == NULL){ 395 | if(count($cmds) > 0){ 396 | if($begin === TRUE && !$initbegin){ return FALSE; } 397 | return $cmds[0]; 398 | } 399 | return FALSE; 400 | } 401 | if($cmd === TRUE){ return $cmds; } 402 | if(is_string($cmd)){ $cmd = [$cmd]; } 403 | if(is_array($cmd)){ 404 | foreach($cmd as $csel){ 405 | if($csel[0] != "/"){ $csel = "/" .$csel; } 406 | $csel = strtolower($csel); 407 | if(in_array($csel, $cmds) && strpos($csel, "@") === FALSE){ 408 | if(is_string($begin)){ 409 | if(!$initbegin){ return FALSE; } // Only commands at begin 410 | $text = strtolower($this->text(FALSE)); // No UTF-8 clean 411 | return (preg_match('/^\\' ."$csel $begin" .'($|\s\w+)/i', $text)); 412 | } 413 | return !($begin && !$initbegin); 414 | } 415 | // Add with bot name 416 | $name = strtolower($this->bot->username); 417 | if($name){ 418 | if($name[0] != "@"){ $name = "@" .$name; } 419 | $csel = $csel.$name; 420 | } 421 | if(in_array($csel, $cmds)){ 422 | if(is_string($begin)){ 423 | if(!$initbegin){ return FALSE; } // Only commands at begin 424 | $text = strtolower($this->text(FALSE)); // No UTF-8 clean 425 | return (preg_match('/^\\' ."$csel $begin" .'($|\s\w+)/i', $text)); 426 | } 427 | return !($begin && !$initbegin); 428 | } 429 | } 430 | } 431 | return FALSE; 432 | } 433 | 434 | public function text_hashtag($tag = NULL){ 435 | // NULL -> saca el primer hashtag o FALSE. 436 | // TRUE -> array [hashtags] 437 | // STR -> hashtag definido. 438 | if(empty($this->entities)){ return FALSE; } 439 | $hgs = array(); 440 | $text = $this->text(FALSE); // No UTF-8 clean 441 | foreach($this->entities as $e){ 442 | if($e->type == 'hashtag'){ $hgs[] = strtolower($e->value); } 443 | } 444 | if($tag == NULL){ return (count($hgs) > 0 ? $hgs[0] : FALSE); } 445 | if($tag === TRUE){ return $hgs; } 446 | if(is_string($tag)){ 447 | if($tag[0] != "#"){ $tag = "#" .$tag; } 448 | return in_array(strtolower($tag), $hgs); 449 | } 450 | return FALSE; 451 | } 452 | 453 | public function text_url($cmd = NULL){ 454 | // NULL -> saca la primera URL o FALSE. 455 | // TRUE -> array [URLs] 456 | if(empty($this->entities)){ return FALSE; } 457 | $cmds = array(); 458 | $text = $this->text(FALSE); // No UTF-8 clean 459 | foreach($this->entities as $e){ 460 | if($e->type == 'url'){ $cmds[] = $e->value; } 461 | } 462 | if($cmd == NULL){ return (count($cmds) > 0 ? $cmds[0] : FALSE); } 463 | if($cmd === TRUE){ return $cmds; } 464 | return FALSE; 465 | } 466 | 467 | public function last_word($clean = FALSE){ 468 | $text = $this->words(TRUE); 469 | if($clean === TRUE){ $clean = 'alphanumeric-accent'; } 470 | return $this->clean($clean, array_pop($text)); 471 | } 472 | 473 | public function words($position = NULL, $amount = 1, $filter = FALSE){ // Contar + recibir argumentos 474 | if($position === NULL){ 475 | return count(explode(" ", $this->text())); 476 | }elseif($position === TRUE){ 477 | return explode(" ", $this->text()); 478 | }elseif(is_numeric($position)){ 479 | if($amount === TRUE){ $filter = 'alphanumeric'; $amount = 1; } 480 | elseif(is_string($amount)){ $filter = $amount; $amount = 1; } 481 | $t = explode(" ", $this->text()); 482 | $a = $position + $amount; 483 | $str = ''; 484 | for($i = $position; $i < $a; $i++){ 485 | $str .= $t[$i] .' '; 486 | } 487 | if($filter !== FALSE){ $str = $this->clean($filter, $str); } 488 | return trim($str); 489 | } 490 | } 491 | 492 | public function word_position($find){ 493 | $text = $this->text(); 494 | if(empty($text)){ return FALSE; } 495 | $pos = strpos($text, $find); 496 | if($pos === FALSE){ return FALSE; } 497 | $text = substr($text, 0, $pos); 498 | return count(explode(" ", $text)); 499 | } 500 | 501 | public function clean($pattern = 'alphanumeric-full', $text = NULL){ 502 | $pats = [ 503 | 'number' => '/^[0-9]+/', 504 | 'number-calc' => '/^([+-]?)\d+(([\.,]?)\d+?)/', 505 | 'alphanumeric' => '/[^a-zA-Z0-9]+/', 506 | 'alphanumeric-accent' => '/[^a-zA-Z0-9áéíóúÁÉÍÓÚàèìòùÀÈÌÒÙ]+/', 507 | 'alphanumeric-symbols-basic' => '/[^a-zA-Z0-9\._\-]+/', 508 | 'alphanumeric-full' => '/[^a-zA-Z0-9áéíóúÁÉÍÓÚàèìòùÀÈÌÒÙ\._\-]+/', 509 | 'alphanumeric-full-spaces' => '/[^a-zA-Z0-9áéíóúÁÉÍÓÚàèìòùÀÈÌÒÙ\.\s_\-]+/', 510 | ]; 511 | if(empty($text)){ $text = $this->text(); } 512 | if($pattern == FALSE){ return $text; } 513 | if(!isset($pats[$pattern])){ return FALSE; } 514 | return preg_replace($pats[$pattern], "", $text); 515 | } 516 | 517 | /** 518 | * Return date of message. 519 | * TRUE = diff time() - Telegram timestamp. 520 | * NULL = return date format. 521 | * int = diff int time() - Telegram timestamp. 522 | * string date = diff date - Telegram timestamp. 523 | * string date_format = return specified date format. 524 | */ 525 | public function date($parse = NULL, $time = NULL){ 526 | if(empty($time)){ $time = $this->timestamp; } 527 | if(empty($time)){ $time = time(); } // TEMP HACK Si no hay timestamp. 528 | 529 | if($parse === NULL){ return date("Y-m-d H:i:s", $time); } 530 | elseif($parse === TRUE){ $parse = time(); } 531 | 532 | if(is_numeric($parse)){ 533 | // timestamp, diff time. 534 | return ($parse - $time); 535 | }else{ 536 | $date = strtotime($parse); 537 | if($date > 0){ 538 | // Diff with timestamp 539 | return ($date - $time); 540 | } 541 | // Parse date format 542 | return date($parse, $time); 543 | } 544 | } 545 | 546 | public function progressbar($val, $max = 100, $chars = 12, $chfull = NULL, $chempty = NULL){ 547 | $chfull = (empty($chfull) ? "\u{2588}" : $this->emoji($chfull)); 548 | $chempty = (empty($chempty) ? "\u{2592}" : $this->emoji($chempty)); 549 | 550 | $nfull = floor(($val / $max) * $chars); 551 | if($nfull < 0){ $nfull = 0; } 552 | $nempty = max(($chars - $nfull), 0); 553 | 554 | $str = ""; 555 | for($i = 0; $i < $nfull; $i++){ $str .= $chfull; } 556 | for($i = 0; $i < $nempty; $i++){ $str .= $chempty; } 557 | 558 | return $str; 559 | } 560 | 561 | public function is_chat_group(){ return isset($this->chat->type) && in_array($this->chat->type, ["group", "supergroup"]); } 562 | public function data_received($expect = NULL){ 563 | if($expect !== NULL){ 564 | return (isset($this->data[$this->key][$expect])); 565 | } 566 | $data = [ 567 | "migrate_to_chat_id", "migrate_from_chat_id", 568 | "new_chat_participant", "left_chat_participant", "new_chat_members", "new_chat_member", "left_chat_member", 569 | "reply_to_message", "text", "audio", "document", "photo", "video_note", "voice", "location", "contact" 570 | ]; 571 | foreach($data as $t){ 572 | if(isset($this->data[$this->key][$t])){ 573 | if($expect == NULL or $expect == $t){ return $t; } 574 | } 575 | } 576 | return FALSE; 577 | } 578 | 579 | public function forward_type($expect = NULL){ 580 | if(!$this->has_forward){ return FALSE; } 581 | $type = $this->data['message']['forward_from_chat']['type']; 582 | if($expect !== NULL){ return (strtolower($expect) == $type); } 583 | return $type; 584 | } 585 | 586 | public function is_bot($user = NULL){ 587 | if($user === NULL){ $user = $this->user->username; } 588 | elseif($user === TRUE && $this->has_reply){ $user = $this->reply_user->username; } 589 | elseif($user instanceof User){ 590 | if($user->is_bot){ return $user->is_bot; } 591 | $user = $user->username; 592 | } 593 | return (!empty($user) && substr(strtolower($user), -3) == "bot"); 594 | // TODO Si realmente es un bot y se intenta hacer un chatAction, no debería dejar. 595 | // A no ser que ese usuario también haya bloqueado al bot. 596 | } 597 | 598 | // NOTE: Solo funcionará si el bot está en el grupo. 599 | public function user_in_chat(&$user, $chat = NULL, $object = FALSE){ 600 | if($chat === TRUE){ $object = TRUE; $chat = NULL; } 601 | if(empty($chat)){ $chat = $this->chat; } 602 | if($chat instanceof Chat){ $chat = $chat->id; } 603 | 604 | $uid = $user; 605 | if($user instanceof User){ $uid = $user->id; } 606 | $info = $this->send->get_member_info($uid, $chat); 607 | $ret = ($object ? (object) $info : $info); 608 | 609 | // TODO CHECK DATA 610 | if($user instanceof User && $info !== FALSE){ 611 | $user->status = $info['status']; 612 | } 613 | 614 | if( 615 | $info === FALSE or 616 | in_array($info['status'], ['left', 'kicked']) or 617 | ( 618 | $info['status'] == 'restricted' and 619 | $info['until_date'] == 0 and 620 | !$info['can_send_messages'] 621 | ) 622 | ){ return FALSE; } 623 | 624 | return TRUE; 625 | } 626 | 627 | // TODO Join function and deprecate 628 | public function grouplink($text, $url = FALSE){ 629 | $link = "https://t.me/"; 630 | if($text[0] != "@" and strlen($text) == 22){ 631 | $link .= "joinchat/$text"; 632 | }else{ 633 | if($url && $text[0] == "@"){ $link .= substr($text, 1); } 634 | else{ $link = $text; } 635 | } 636 | return $link; 637 | } 638 | 639 | public function userlink($user, $text = NULL, $html = TRUE){ 640 | if($user instanceof User){ $user = $user->id; } 641 | $link = "tg://user?id=" .$user; 642 | if(empty($text)){ return $link; } 643 | if($html){ return '' .$text .''; } 644 | return '[' .$text .'](' .$link .')'; 645 | } 646 | 647 | public function get_chat_link($chat = NULL){ 648 | if(empty($chat)){ $chat = $this->chat->id; } 649 | return $this->send->get_chat_link($chat); 650 | } 651 | 652 | public function answer_if_callback($text = "", $alert = FALSE){ 653 | if($this->key != "callback_query"){ return FALSE; } 654 | return $this->send 655 | ->text($text) 656 | ->answer_callback($alert); 657 | } 658 | 659 | public function dump($json = FALSE){ return($json ? json_encode($this->data) : $this->data); } 660 | 661 | public function get_admins($chat = NULL, $full = FALSE){ 662 | $ret = array(); 663 | if(empty($chat)){ $chat = $this->chat->id; } 664 | $admins = $this->send->get_admins($chat); 665 | if(!empty($admins)){ 666 | foreach($admins as $a){ $ret[] = $a['user']->id; } 667 | } 668 | return ($full == TRUE ? $admins : $ret); 669 | } 670 | 671 | public function data($type, $object = TRUE){ 672 | $accept = ["text", "audio", "video", "video_note", "document", "photo", "voice", "location", "contact"]; 673 | $type = strtolower($type); 674 | if(in_array($type, $accept) && isset($this->data['message'][$type])){ 675 | if($object){ return (object) $this->data['message'][$type]; } 676 | return $this->data['message'][$type]; 677 | } 678 | return FALSE; 679 | } 680 | 681 | public function _generic_content($key, $object = NULL, $rkey = 'file_id'){ 682 | if(!isset($this->data[$this->key][$key])){ return FALSE; } 683 | $data = $this->data[$this->key][$key]; 684 | if(empty($data)){ return FALSE; } 685 | if($object === TRUE){ return (object) $data; } 686 | elseif($object === FALSE){ return array_values($data); } 687 | 688 | if(in_array($key, ["document", "location", "game"])){ return $data; } 689 | return $data[$rkey]; 690 | } 691 | 692 | public function document($object = TRUE){ return $this->_generic_content('document', $object); } 693 | public function location($object = TRUE){ return $this->_generic_content('location', $object); } 694 | public function audio($object = NULL){ return $this->_generic_content('audio', $object); } 695 | public function voice($object = NULL){ return $this->_generic_content('voice', $object); } 696 | public function video($object = NULL){ return $this->_generic_content('video', $object); } 697 | public function video_note($object = NULL){ return $this->_generic_content('video_note', $object); } 698 | public function sticker($object = NULL){ return $this->_generic_content('sticker', $object); } 699 | public function game($object = TRUE){ return $this->_generic_content('game', $object); } 700 | 701 | public function gif(){ 702 | $gif = $this->document(TRUE); 703 | if(!$gif or !in_array($gif->mime_type, ["video/mp4"])){ return FALSE; } 704 | // TODO gif viene por size? 705 | return $gif->file_id; 706 | } 707 | 708 | public function photo($retall = FALSE, $sel = -1){ 709 | if(!isset($this->data['message']['photo'])){ return FALSE; } 710 | $photos = $this->data['message']['photo']; 711 | if(empty($photos)){ return FALSE; } 712 | // Select last file or $sel_id 713 | $sel = ($sel == -1 or ($sel > count($photos) - 1) ? (count($photos) - 1) : $sel); 714 | if(!isset($photos[$sel])){ $sel = 0; } // TEMP FIX 715 | if($retall === FALSE){ return $photos[$sel]['file_id']; } 716 | elseif($retall === TRUE){ return (object) $photos[$sel]; } 717 | } 718 | 719 | public function contact($self = FALSE, $object = TRUE){ 720 | $contact = $this->data['message']['contact']; 721 | if(empty($contact)){ return FALSE; } 722 | if( 723 | $self == FALSE or 724 | ($self == TRUE && $this->user->id == $contact['user_id']) 725 | ){ 726 | if($object == TRUE){ return (object) $contact; } 727 | return $contact; 728 | }elseif($self == TRUE){ 729 | return FALSE; 730 | } 731 | } 732 | 733 | public function reply_target($priority = NULL){ 734 | if(!$this->has_reply){ return NULL; } 735 | // El reply puede ser hacia la persona del mensaje al cual se hace reply 736 | // o si es un forward, hacia ese usuario creador del mensaje. 737 | 738 | $ret = $this->reply_user; 739 | if($priority == NULL or $priority == TRUE or strtolower($priority) == 'forward'){ 740 | if($this->reply_is_forward){ 741 | $ret = $this->reply->forward_from; 742 | } 743 | } 744 | 745 | return $ret; 746 | } 747 | 748 | // Return UserID siempre que sea posible. 749 | public function user_selector($priority = NULL, $word = NULL){ 750 | $user = $this->reply_target($priority); 751 | if(!empty($user)){ return $user->id; } 752 | // TODO 753 | } 754 | 755 | public function pinned_message($content = NULL){ 756 | if(!isset($this->data['message']['pinned_message'])){ return FALSE; } 757 | $pin = $this->data['message']['pinned_message']; 758 | if($content === NULL){ 759 | $user = (object) $pin['from']; 760 | $chat = (object) $pin['chat']; 761 | $data = $pin['text']; 762 | return (object) array( 763 | 'user' => $user, 764 | 'chat' => $chat, 765 | 'data' => $data 766 | ); 767 | } 768 | elseif($content === TRUE){ return $pin['text']; } 769 | elseif($content === FALSE){ return $this->send->pin_message(FALSE); } 770 | } 771 | 772 | public function user_can($action = NULL, $user = NULL, $chat = NULL){ 773 | if(empty($user)){ $user = $this->user->id; } 774 | if(empty($chat)){ $chat = $this->chat->id; } 775 | $data = $this->send->get_member_info($user, $chat); 776 | 777 | $can = [ 778 | 'can_be_edited', 'can_change_info', 779 | 'can_post_messages', 'can_edit_messages', 780 | 'can_delete_messages', 'can_invite_users', 781 | 'can_restrict_members', 'can_pin_messages', 782 | 'can_promote_members', 'can_send_messages', 783 | 'can_send_media_messages', 'can_send_other_messages', 784 | 'can_add_web_page_previews' 785 | ]; 786 | 787 | // Return all results. 788 | if($action === TRUE or $action === NULL){ 789 | $final = array(); 790 | foreach($can as $c){ 791 | if(isset($data['result'][$c])){ $final[$c] = $data['result'][$c]; } 792 | } 793 | return $final; 794 | } 795 | 796 | if(strpos($action, "can_") === FALSE){ $action = "can_" .$action; } 797 | $action = strtolower($action); 798 | 799 | if(!isset($data['result'][$action])){ return NULL; } 800 | return (bool) $data['result'][$action]; 801 | } 802 | 803 | public function download($file_id, $path = NULL){ 804 | $data = $this->send->get_file($file_id); 805 | $url = "https://api.telegram.org/file/bot" .$this->bot->id .":" .$this->bot->key ."/"; 806 | $file = $url .$data['file_path']; 807 | if(!empty($path)){ 808 | return file_put_contents($path, file_get_contents($file)); 809 | } 810 | return $file; 811 | } 812 | 813 | public function emoji($text, $reverse = FALSE){ 814 | // Load when used 815 | if(empty($this->emojis)){ 816 | $this->emojis = require 'Emojis.php'; 817 | } 818 | 819 | if(!$reverse){ 820 | // TODO Needs delimiter /--/ 821 | /* return preg_replace_callback(array_keys($this->emojis), function ($mts){ 822 | return $this->emojis[$mts[1]]; 823 | }, $text); */ 824 | return str_ireplace(array_keys($this->emojis), array_values($this->emojis), $text); 825 | } 826 | 827 | // TODO 828 | return substr(json_encode($text), 1, -1); // No comas 829 | } 830 | } 831 | 832 | ?> 833 | -------------------------------------------------------------------------------- /src/Sender.php: -------------------------------------------------------------------------------- 1 | _keyboard = new \Telegram\Keyboards\Keyboard($this); 23 | $this->_inline = new \Telegram\Keyboards\InlineKeyboard($this); 24 | $this->_payment = new \Telegram\Payments\Stripe($this); 25 | $this->_sticker = new \Telegram\Sticker($this); 26 | 27 | if(!empty($uid)){ 28 | if($uid instanceof Receiver){ 29 | $this->parent = $uid; 30 | $this->bot = $this->parent->bot; 31 | $this->language = $this->parent->language; 32 | }elseif($uid instanceof Bot){ 33 | $this->bot = $uid; 34 | }else{ 35 | $this->set_access($uid, $key, $name); 36 | } 37 | } 38 | } 39 | 40 | private function set_access($uid, $key = NULL, $name = NULL){ 41 | $this->bot = new \Telegram\Bot($uid, $key, $name); 42 | return $this; 43 | } 44 | 45 | public function chat($id = NULL){ 46 | if(empty($id)){ 47 | if(isset($this->content['chat_id'])){ return $this->content['chat_id']; } 48 | $id = TRUE; // HACK ? 49 | } 50 | if($id === TRUE && $this->parent instanceof \Telegram\Receiver){ $id = $this->parent->chat->id; } 51 | elseif($id instanceof Chat or $id instanceof User){ $id = $id->id; } 52 | $this->content['chat_id'] = $id; 53 | return $this; 54 | } 55 | 56 | public function chats($ids){ 57 | if(empty($ids)){ return $this; } // HACK 58 | $this->broadcast = $ids; 59 | $this->content['chat_id'] = $ids[0]; // HACK 60 | return $this; 61 | } 62 | 63 | public function user($id = NULL){ 64 | if(empty($id)){ return $this->content['user_id']; } 65 | elseif($id === TRUE){ $id = $this->parent->user->id; } 66 | elseif($id instanceof User){ $id = $id->id; } 67 | $this->content['user_id'] = $id; 68 | return $this; 69 | } 70 | 71 | public function message($id = NULL){ 72 | if(empty($id)){ return $this->content['message_id']; } 73 | if($id === TRUE && $this->parent instanceof \Telegram\Receiver){ $id = $this->parent->message; } 74 | elseif(is_array($id) and isset($id['message_id'])){ $id = $id['message_id']; } // JSON Response from another message. 75 | $this->content['message_id'] = $id; 76 | return $this; 77 | } 78 | 79 | public function get_file($id){ 80 | $this->method = "getFile"; 81 | $this->content['file_id'] = $id; 82 | return $this->send(); 83 | } 84 | 85 | public function duration($duration){ 86 | $this->content['duration'] = (int) $duration; 87 | return $this; 88 | } 89 | 90 | public function resolution($width, $height){ 91 | $this->content['width'] = (int) $width; 92 | $this->content['height'] = (int) $height; 93 | return $this; 94 | } 95 | 96 | public function file($type, $file, $caption = NULL, $keep = FALSE){ 97 | if(!in_array($type, ["photo", "chatphoto", "audio", "voice", "document", "animation", "sticker", "video", "video_note", "videonote"])){ return FALSE; } 98 | 99 | $url = FALSE; 100 | if(filter_var($file, FILTER_VALIDATE_URL) !== FALSE){ 101 | // ES URL, descargar y enviar. 102 | $url = TRUE; 103 | if($caption !== TRUE){ 104 | $tmp = tempnam("/tmp", "telegram") .substr($file, -4); // .jpg 105 | file_put_contents($tmp, fopen($file, 'r')); 106 | $file = $tmp; 107 | }else{ 108 | $caption = NULL; 109 | } 110 | } 111 | 112 | $this->method = "send" .ucfirst(strtolower($type)); 113 | if(in_array($type, ["videonote", "video_note"])){ 114 | $type = "video_note"; 115 | $this->method = "sendVideoNote"; 116 | }elseif($type == "chatphoto"){ 117 | $type = "photo"; 118 | $this->method = "sendChatPhoto"; 119 | } 120 | if(file_exists(realpath($file))){ 121 | $this->content[$type] = new \CURLFile(realpath($file)); 122 | }else{ 123 | $this->content[$type] = $file; 124 | } 125 | if($caption === NULL && isset($this->content['text'])){ 126 | $caption = $this->content['text']; 127 | unset($this->content['text']); 128 | } 129 | if($caption !== NULL){ 130 | $key = "caption"; 131 | if($type == "audio"){ $key = "title"; } 132 | $this->content[$key] = $caption; 133 | } 134 | 135 | $output = $this->send("POSTKEEP"); 136 | if($url === TRUE){ unlink($file); } 137 | if($keep === FALSE){ $this->_reset(); } 138 | if(!empty($output) && is_string($output)){ 139 | $json = json_decode($output, TRUE); 140 | if($json){ return $json['result']; } 141 | } 142 | return $output; 143 | // return $this; 144 | } 145 | 146 | public function location($lat, $lon = NULL, $live_period = NULL){ 147 | if($live_period == NULL && $lon != NULL){ $live_period = $lon; } 148 | if(is_array($lat) && $lon == NULL){ $lon = $lat[1]; $lat = $lat[0]; } 149 | elseif(is_string($lat) && strpos($lat, ",") !== FALSE){ 150 | $lat = explode(",", $lat); 151 | $lon = trim($lat[1]); 152 | $lat = trim($lat[0]); 153 | } 154 | $this->content['latitude'] = $lat; 155 | $this->content['longitude'] = $lon; 156 | if( 157 | is_numeric($live_period) && !is_float($live_period) && 158 | $live_period >= 60 && $live_period <= 86400 159 | ){ 160 | $this->content['live_period'] = (int) $live_period; 161 | } 162 | $this->method = "sendLocation"; 163 | return $this; 164 | } 165 | 166 | public function venue($title, $address, $foursquare = NULL){ 167 | if(isset($this->content['latitude']) && isset($this->content['longitude'])){ 168 | $this->content['title'] = $title; 169 | $this->content['address'] = $address; 170 | if(!empty($foursquare)){ $this->content['foursquare_id'] = $foursquare; } 171 | $this->method = "sendVenue"; 172 | } 173 | return $this; 174 | } 175 | 176 | public function dump($user){ 177 | var_dump($this->method); var_dump($this->content); 178 | $bm = $this->method; 179 | $bc = $this->content; 180 | 181 | $this->_reset(); 182 | $this 183 | ->chat($user) 184 | ->text(json_encode($bc)) 185 | ->send(); 186 | $this->method = $bm; 187 | $this->content = $bc; 188 | return $this; 189 | } 190 | 191 | public function contact($phone, $first_name, $last_name = NULL){ 192 | $this->content['phone_number'] = $phone; 193 | $this->content['first_name'] = $first_name; 194 | if(!empty($last_name)){ $this->content['last_name'] = $last_name; } 195 | $this->method = "sendContact"; 196 | return $this; 197 | } 198 | 199 | public function language($set){ 200 | $this->language = $set; 201 | return $this; 202 | } 203 | 204 | public function text($text, $type = NULL){ 205 | if(is_array($text)){ 206 | if(isset($text[$this->language])){ 207 | $text = $text[$this->language]; 208 | }elseif(isset($text["en"])){ 209 | $text = $text["en"]; 210 | }else{ 211 | $text = current($text); // First element. 212 | } 213 | } 214 | 215 | if($this->convert_emoji){ $text = $this->parent->emoji($text); } 216 | $this->content['text'] = $text; 217 | $this->method = "sendMessage"; 218 | if($type === TRUE){ $this->content['parse_mode'] = 'Markdown'; } 219 | elseif(in_array($type, ['Markdown', 'HTML'])){ $this->content['parse_mode'] = $type; } 220 | elseif($text != strip_tags($text)){ $this->content['parse_mode'] = 'HTML'; } // Autodetect HTML. 221 | 222 | return $this; 223 | } 224 | 225 | public function text_replace($text, $replace, $type = NULL){ 226 | if(is_array($text)){ 227 | if(isset($text[$this->language])){ 228 | $text = $text[$this->language]; 229 | }elseif(isset($text["en"])){ 230 | $text = $text["en"]; 231 | }else{ 232 | $text = current($text); // First element. 233 | } 234 | } 235 | 236 | if(strpos($text, "%s") !== FALSE){ 237 | if(!is_array($replace)){ $replace = [$replace]; } 238 | $pos = 0; 239 | foreach($replace as $r){ 240 | $pos = strpos($text, "%s", $pos); 241 | if($pos === FALSE){ break; } 242 | $text = substr_replace($text, $r, $pos, 2); // 2 = strlen("%s") 243 | } 244 | }else{ 245 | $text = str_replace(array_keys($replace), array_values($replace), $text); 246 | } 247 | 248 | return $this->text($text, $type); 249 | } 250 | 251 | public function keyboard(){ return $this->_keyboard; } 252 | public function inline_keyboard(){ return $this->_inline; } 253 | public function payment($provider = "Stripe"){ 254 | $this->_payment = new \Telegram\Payments\Stripe($this); 255 | return $this->_payment; 256 | } 257 | public function sticker($id = NULL){ 258 | if(!empty($id)){ return $this->file('sticker', $id); } 259 | return $this->_sticker; 260 | } 261 | 262 | public function sticker_set($name, $chat = TRUE){ 263 | $this->chat($chat); 264 | if(!empty($name)){ $this->content['sticker_set_name'] = $name; } 265 | $this->method = (empty($name) ? "delete" : "set") ."ChatStickerSet"; 266 | return $this->send(); 267 | } 268 | 269 | public function payment_precheckout($id, $ok = TRUE){ 270 | $this->content['pre_checkout_query_id'] = $id; 271 | if($ok === TRUE){ 272 | $this->content['ok'] = TRUE; 273 | }else{ 274 | $this->content['ok'] = FALSE; 275 | $this->content['error_message'] = $ok; 276 | } 277 | 278 | $this->method = "answerPreCheckoutQuery"; 279 | return $this->send(); 280 | } 281 | 282 | public function force_reply($selective = TRUE){ 283 | $this->content['reply_markup'] = ['force_reply' => TRUE, 'selective' => $selective]; 284 | return $this; 285 | } 286 | 287 | public function caption($text){ 288 | $this->content['caption'] = $text; 289 | return $this; 290 | } 291 | 292 | public function disable_web_page_preview($value = FALSE){ 293 | if($value === TRUE){ $this->content['disable_web_page_preview'] = TRUE; } 294 | return $this; 295 | } 296 | 297 | public function notification($value = TRUE){ 298 | if($value === FALSE){ $this->content['disable_notification'] = TRUE; } 299 | else{ if(isset($this->content['disable_notification'])){ unset($this->content['disable_notification']); } } 300 | return $this; 301 | } 302 | 303 | public function reply_to($message_id = NULL){ 304 | if(is_bool($message_id) && $this->parent instanceof Receiver){ 305 | if($message_id === TRUE or ($message_id === FALSE && !$this->parent->has_reply)){ $message_id = $this->parent->message; } 306 | elseif($message_id === FALSE){ 307 | if(!$this->parent->has_reply){ return; } 308 | $message_id = $this->parent->reply->message_id; 309 | } 310 | } 311 | $this->content['reply_to_message_id'] = $message_id; 312 | return $this; 313 | } 314 | 315 | public function forward_to($chat_id_to){ 316 | if(empty($this->chat()) or empty($this->content['message_id'])){ return $this; } 317 | $this->content['from_chat_id'] = $this->chat(); 318 | $this->chat($chat_id_to); 319 | $this->method = "forwardMessage"; 320 | 321 | return $this; 322 | } 323 | 324 | public function chat_action($type){ 325 | $actions = [ 326 | 'typing', 'upload_photo', 'record_video', 'upload_video', 'record_audio', 'upload_audio', 327 | 'upload_document', 'find_location', 'record_video_note', 'upload_video_note' 328 | ]; 329 | if(!in_array($type, $actions)){ $type = $actions[0]; } // Default is typing 330 | $this->content['action'] = $type; 331 | $this->method = "sendChatAction"; 332 | return $this; 333 | } 334 | 335 | public function until_date($until){ 336 | if(!is_numeric($until) and strtotime($until) !== FALSE){ $until = strtotime($until); } 337 | $this->content['until_date'] = $until; 338 | return $this; 339 | } 340 | 341 | public function kick($user = NULL, $chat = NULL, $keep = FALSE){ 342 | $this->ban($user, $chat, $keep); 343 | return $this->unban($user, $chat, $keep); 344 | } 345 | 346 | public function restrict($option = NULL, $user = NULL, $chat = NULL){ 347 | if(!empty($option) and strpos($option, "can_") === FALSE){ $option = "can_" . strtolower($option); } 348 | $this->method = "restrictChatMember"; 349 | 350 | /* send_messages, send_media_messages, 351 | send_other_messages, add_web_page_previews */ 352 | 353 | if($option == "can_none"){ // restrict none 354 | $this->content['can_send_other_messages'] = TRUE; 355 | $this->content['can_add_web_page_previews'] = TRUE; 356 | }elseif($option == "can_all"){ // restrict all = ban 357 | return $this->ban($user, $chat); 358 | }elseif(!empty($option)){ 359 | $this->content[$option] = TRUE; 360 | } 361 | 362 | return $this->send(); 363 | } 364 | 365 | public function restrict_until($until, $option = NULL, $user = NULL, $chat = NULL){ 366 | return $this 367 | ->until_date($until) 368 | ->restrict($option, $user, $chat); 369 | } 370 | 371 | public function ban_until($until, $user = NULL, $chat = NULL, $keep = FALSE){ 372 | return $this 373 | ->until_date($until) 374 | ->ban($user, $chat, $keep); 375 | } 376 | 377 | public function ban($user = NULL, $chat = NULL, $keep = FALSE){ return $this->_parse_generic_chatFunctions("kickChatMember", $keep, $chat, $user); } 378 | public function unban($user = NULL, $chat = NULL, $keep = FALSE){ return $this->_parse_generic_chatFunctions("unbanChatMember", $keep, $chat, $user); } 379 | public function leave_chat($chat = NULL, $keep = FALSE){ return $this->_parse_generic_chatFunctions("leaveChat", $keep, $chat); } 380 | public function get_chat($chat = NULL, $keep = FALSE){ 381 | $res = $this->_parse_generic_chatFunctions("getChat", $keep, $chat); 382 | if($res !== FALSE){ $res['user'] = new User($res['user']); } 383 | return $res; 384 | } 385 | public function get_admins($chat = NULL, $keep = FALSE){ 386 | $res = $this->_parse_generic_chatFunctions("getChatAdministrators", $keep, $chat); 387 | if($res !== FALSE){ 388 | foreach($res as $k => $data){ 389 | $res[$k]['user'] = new User($data['user']); 390 | } 391 | } 392 | return $res; 393 | } 394 | public function get_member_info($user = NULL, $chat = NULL, $keep = FALSE){ 395 | $res = $this->_parse_generic_chatFunctions("getChatMember", $keep, $chat, $user); 396 | if($res !== FALSE){ $res['user'] = new User($res['user']); } 397 | return $res; 398 | } 399 | public function get_members_count($chat = NULL, $keep = FALSE){ return $this->_parse_generic_chatFunctions("getChatMembersCount", $keep, $chat); } 400 | public function get_chat_link($chat = NULL, $keep = FALSE){ return $this->_parse_generic_chatFunctions("exportChatInviteLink", $keep, $chat); } 401 | public function get_user_avatar($user = NULL, $offset = NULL, $limit = 100){ 402 | if(!empty($user)){ $this->user($user); } 403 | $this->content['offset'] = $offset; 404 | $this->content['limit'] = $limit; 405 | $this->method = "getUserProfilePhotos"; 406 | 407 | $res = $this->send($keep); 408 | if(!isset($res['photos']) or empty($res['photos'])){ return FALSE; } 409 | return $res['photos']; 410 | } 411 | 412 | public function set_title($text){ 413 | $this->method = "setChatTitle"; 414 | if($this->convert_emoji){ $text = $this->parent->emoji($text); } 415 | $this->content['title'] = $text; 416 | return $this->send(); 417 | } 418 | 419 | public function set_description($text = ""){ 420 | $this->method = "setChatDescription"; 421 | if($this->convert_emoji){ $text = $this->parent->emoji($text); } 422 | $this->content['description'] = $text; 423 | return $this->send(); 424 | } 425 | 426 | public function set_photo($path = FALSE){ 427 | if($path === NULL or $path === FALSE){ 428 | $this->method = "deleteChatPhoto"; 429 | return $this->send(); 430 | } 431 | return $this->file("chatphoto", $path); 432 | } 433 | 434 | public function promote($vars, $user = NULL, $defval = TRUE){ 435 | if(!empty($user)){ $this->user($user); } 436 | if(!is_array($vars)){ $vars = [$vars]; } 437 | 438 | /* post_messages, edit_messages, delete_messages, pin_messages, 439 | change_info, invite_users, restrict_members, promote_members */ 440 | 441 | $this->method = "promoteChatMember"; 442 | foreach($vars as $k => $v){ 443 | $key = (is_numeric($k) ? $v : $k); 444 | $value = (!is_numeric($k) and is_bool($v) ? $v : $defval); 445 | 446 | if(strpos($key, "can_") === FALSE){ $key = "can_" . $key; } 447 | $key = strtolower($key); 448 | 449 | $this->content[$key] = (bool) $value; 450 | } 451 | 452 | return $this; 453 | } 454 | 455 | // Alias for promote but negative 456 | public function demote($vars, $user = NULL){ return $this->promote($vars, $user, FALSE); } 457 | 458 | public function pin_message($message = NULL){ 459 | $this->method = "pinChatMessage"; 460 | 461 | if($message === FALSE){ 462 | $this->method = "un" . $this->method; // unpin 463 | return $this->send(); 464 | } 465 | 466 | if(!empty($message)){ $this->message($message); } 467 | return $this->send(); 468 | } 469 | 470 | // DEBUG 471 | /* function get_message($message, $chat = NULL){ 472 | $this->method = 'getMessage'; 473 | if(empty($chat) && !isset($this->content['chat_id'])){ 474 | $this->content['chat_id'] = $this->parent->chat->id; 475 | } 476 | 477 | return $this->send(); 478 | } */ 479 | 480 | public function answer_callback($alert = FALSE, $text = NULL, $id = NULL){ 481 | // Function overload :> 482 | // $this->text can be empty. (Answer callback with empty response to finish request.) 483 | if($text == NULL && $id == NULL){ 484 | $text = $this->content['text']; 485 | if($this->parent instanceof Receiver && $this->parent->key == "callback_query"){ 486 | $id = $this->parent->id; 487 | } 488 | if(empty($id)){ return $this; } // HACK 489 | $this->content['callback_query_id'] = $id; 490 | if($this->convert_emoji){ $text = $this->parent->emoji($text); } 491 | $this->content['text'] = $text; 492 | $this->content['show_alert'] = $alert; 493 | $this->method = "answerCallbackQuery"; 494 | } 495 | 496 | return $this->send(); 497 | } 498 | 499 | public function media($type, $media, $extras = NULL){ 500 | if(!in_array($type, ['photo', 'video', 'animation', 'audio', 'document'])){ return FALSE; } 501 | // TODO upload media file 502 | $data = [ 503 | 'type' => $type, 504 | 'media' => $media 505 | ]; 506 | 507 | // Change text to caption 508 | if(isset($this->content['text'])){ 509 | $this->content['caption'] = $this->content['text']; 510 | unset($this->content['text']); 511 | } 512 | 513 | // Move current set data to media 514 | foreach(['caption', 'parse_mode'] as $key){ 515 | if(isset($this->content[$key])){ 516 | $data[$key] = $this->content[$key]; 517 | unset($this->content[$key]); 518 | } 519 | } 520 | 521 | // Set extra data 522 | if(is_array($extras)){ 523 | foreach($extras as $k => $v){ 524 | $data[$k] = $v; 525 | } 526 | } 527 | 528 | $this->content['media'] = $data; 529 | return $this; 530 | } 531 | 532 | public function edit($type){ 533 | // if(!in_array($type, ['text', 'message', 'caption', 'keyboard', 'inline', 'markup', 'location', 'livelocation'])){ return FALSE; } 534 | if(isset($this->content['text']) && in_array($type, ['text', 'message'])){ 535 | $this->method = "editMessageText"; 536 | }elseif($type == "caption"){ 537 | $this->method = "editMessageCaption"; 538 | if(array_key_exists('text', $this->content) and !isset($this->content['caption'])){ 539 | $this->content['caption'] = $this->content['text']; 540 | unset($this->content['text']); 541 | } 542 | if(!isset($this->content['caption'])){ return FALSE; } 543 | }elseif(isset($this->content['inline_keyboard']) && in_array($type, ['keyboard', 'inline', 'markup'])){ 544 | $this->method = "editMessageReplyMarkup"; 545 | }elseif(isset($this->content['latitude']) && isset($this->content['longitude']) && in_array($type, ['location', 'livelocation'])){ 546 | $this->method = "editMessageLiveLocation"; 547 | }elseif(in_array($type, ['location', 'livelocation'])){ 548 | $this->method = "stopMessageLiveLocation"; 549 | }elseif(isset($this->content['media']) && $type == 'media'){ 550 | $this->method = "editMessageMedia"; 551 | }else{ 552 | return FALSE; 553 | } 554 | 555 | return $this->send(); 556 | } 557 | 558 | public function delete($message = NULL, $chat = NULL){ 559 | if($message === TRUE or (empty($message) && !isset($this->content['message_id']))){ 560 | $this->message(TRUE); 561 | }elseif(is_array($message) and isset($message["message_id"])){ 562 | $this->message($message["message_id"]); 563 | }elseif(!empty($message)){ 564 | $this->message($message); 565 | } 566 | 567 | if($message === TRUE or (empty($chat) && !isset($this->content['chat_id']))){ 568 | $this->chat(TRUE); 569 | }elseif(!empty($chat)){ 570 | $this->chat($chat); 571 | } 572 | 573 | $this->method = "deleteMessage"; 574 | return $this->send(); 575 | } 576 | 577 | public function game($name, $notification = FALSE){ 578 | $this->content['game_short_name'] = $name; 579 | $this->content['disable_notification'] = (bool) $notification; 580 | 581 | $this->method = "sendGame"; 582 | return $this; 583 | } 584 | 585 | public function game_score($user, $score = NULL, $force = FALSE, $edit_message = TRUE){ 586 | $this->user($user); 587 | 588 | if($score == NULL){ 589 | $this->method = "getGameHighScores"; 590 | return $this; 591 | } 592 | 593 | $this->content['score'] = (int) $score; 594 | if($force){ $this->content['force'] = (bool) $force; } 595 | if(!$edit_message){ $this->content['disable_edit_message'] = FALSE; } 596 | 597 | $this->method = "setGameScore"; 598 | return $this; 599 | } 600 | 601 | public function _push($key, $val){ 602 | $this->content[$key] = $val; 603 | return $this; 604 | } 605 | 606 | public function _push_method($name){ 607 | $this->method = $name; 608 | return $this; 609 | } 610 | 611 | private function _reset(){ 612 | $this->method = NULL; 613 | $this->content = array(); 614 | } 615 | 616 | private function _url($with_method = FALSE, $host = "api.telegram.org"){ 617 | $url = ("https://$host/bot" .$this->bot->id .':' .$this->bot->key .'/'); 618 | if($with_method){ $url .= $this->method; } 619 | return $url; 620 | } 621 | 622 | public function send($keep = FALSE, $_broadcast = FALSE){ 623 | if($this->timeout > time()){ 624 | sleep($this->timeout - time()); 625 | } 626 | if(!empty($this->broadcast) and !$_broadcast){ 627 | $result = array(); 628 | if(in_array(strtoupper($keep), ["POST", "POSTKEEP"])){ $keep = "POSTKEEP"; } 629 | else{ $keep = TRUE; } 630 | foreach($this->broadcast as $chat){ 631 | $this->chat($chat); 632 | // Send and keep data 633 | $result[] = $this->send($keep, TRUE); 634 | } 635 | return $result; 636 | } 637 | 638 | if(empty($this->method)){ return FALSE; } 639 | if(empty($this->chat()) && $this->parent instanceof Receiver){ $this->chat($this->parent->chat->id); } 640 | 641 | $post = FALSE; 642 | 643 | if(is_string($keep)){ 644 | $keep = strtoupper($keep); 645 | if($keep == "POST"){ $keep = FALSE; $post = TRUE; } 646 | elseif($keep = "POSTKEEP"){ $keep = TRUE; $post = TRUE; } 647 | } 648 | 649 | $result = $this->Request($this->method, $this->content, $post); 650 | if($keep === FALSE){ $this->_reset(); } 651 | return $result; 652 | } 653 | 654 | private function _parse_generic_chatFunctions($action, $keep, $chat, $user = FALSE){ 655 | $this->method = $action; 656 | if($user === FALSE){ // No hay user. 657 | if(empty($chat) && empty($this->chat())){ return FALSE; } 658 | }else{ 659 | if(empty($user) && empty($chat) && (empty($this->chat()) or empty($this->user()))){ return FALSE; } 660 | } 661 | if(!empty($chat)){ $this->chat($chat); } 662 | if(!empty($user)){ $this->user($user); } 663 | return $this->send($keep); 664 | // return $this; 665 | } 666 | 667 | private function RequestWebhook($method, $parameters) { 668 | if (!is_string($method)) { 669 | error_log("Method name must be a string\n"); 670 | return false; 671 | } 672 | 673 | if (!$parameters) { 674 | $parameters = array(); 675 | } else if (!is_array($parameters)) { 676 | error_log("Parameters must be an array\n"); 677 | return false; 678 | } 679 | 680 | $parameters["method"] = $method; 681 | 682 | header("Content-Type: application/json"); 683 | echo json_encode($parameters); 684 | return true; 685 | } 686 | 687 | private function exec_curl_request($handle) { 688 | $response = curl_exec($handle); 689 | 690 | if ($response === false) { 691 | $errno = curl_errno($handle); 692 | $error = curl_error($handle); 693 | error_log("Curl returned error $errno: $error\n"); 694 | curl_close($handle); 695 | return false; 696 | } 697 | 698 | $http_code = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE)); 699 | curl_close($handle); 700 | 701 | if ($http_code >= 500) { 702 | // do not wat to DDOS server if something goes wrong 703 | sleep(10); 704 | return false; 705 | } else if ($http_code != 200) { 706 | $response = json_decode($response, true); 707 | error_log("Request has failed with error {$response['error_code']}: {$response['description']}\n"); 708 | if ($http_code == 429) { 709 | if(isset($response['parameters']['retry_after'])){ 710 | $this->timeout = time() + (int) $response['parameters']['retry_after']; 711 | } 712 | } else if ($http_code == 401) { 713 | throw new \Exception('Invalid access token provided'); 714 | } 715 | return false; 716 | } else { 717 | $response = json_decode($response, true); 718 | if (isset($response['description'])) { 719 | error_log("Request was successfull: {$response['description']}\n"); 720 | } 721 | $response = $response['result']; 722 | } 723 | 724 | return $response; 725 | } 726 | 727 | private function Request($method, $parameters, $post = FALSE) { 728 | if (!is_string($method)) { 729 | error_log("Method name must be a string\n"); 730 | return false; 731 | } 732 | 733 | if (!$parameters) { 734 | $parameters = array(); 735 | } else if (!is_array($parameters)) { 736 | error_log("Parameters must be an array\n"); 737 | return false; 738 | } 739 | 740 | foreach ($parameters as $key => &$val) { 741 | // encoding to JSON array parameters, for example reply_markup 742 | if (!is_numeric($val) && !is_string($val) && !($val instanceof \CURLFile) ) { 743 | $val = json_encode($val); 744 | } 745 | } 746 | 747 | $url = $this->_url(TRUE); 748 | if(!$post){ $url .= '?'.http_build_query($parameters); } 749 | 750 | $handle = curl_init($url); 751 | curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE); 752 | curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5); 753 | curl_setopt($handle, CURLOPT_TIMEOUT, 60); 754 | if($this->use_internal_resolver){ 755 | $apihosts = [ 756 | "149.154.167.220" 757 | ]; 758 | 759 | $apihost = $apihosts[mt_rand(0,count($apihosts) - 1)]; 760 | curl_setopt($handle, CURLOPT_RESOLVE, ["api.telegram.org:443:$apihost"]); 761 | } 762 | 763 | if($post){ 764 | curl_setopt($handle, CURLOPT_HTTPHEADER, ["Content-Type:multipart/form-data"]); 765 | curl_setopt($handle, CURLOPT_POSTFIELDS, $parameters); 766 | } 767 | 768 | return $this->exec_curl_request($handle); 769 | } 770 | } 771 | 772 | ?> 773 | -------------------------------------------------------------------------------- /src/Sticker.php: -------------------------------------------------------------------------------- 1 | parent = $parent; 13 | } 14 | 15 | public function get_set($name){ 16 | return $this->parent 17 | ->_push_method("getStickerSet") 18 | ->_push('name', $name) 19 | ->send(); 20 | } 21 | 22 | // user = ID or TRUE to get file_id 23 | public function upload($file, $user = NULL){ 24 | $retid = FALSE; 25 | if($user === TRUE){ 26 | $retid = TRUE; $user = NULL; 27 | } 28 | if(empty($user)){ $user = $this->parent->user(); } 29 | if(filter_var($file, FILTER_VALIDATE_URL)){ 30 | // TODO download temp file and upload 31 | }elseif(!file_exists($file) or !is_readable($file)){ 32 | return FALSE; 33 | } 34 | 35 | $response = $this->parent 36 | ->_push_method("uploadStickerFile") 37 | ->_push('png_sticker', new \CURLFile(realpath($file))) 38 | ->send(); 39 | 40 | if($response !== FALSE){ 41 | // TODO set file_id here 42 | } 43 | if($retid){ return $response; } 44 | return $this; 45 | } 46 | 47 | public function delete($file = NULL){ 48 | if(empty($file) and !empty($this->file_id)){ 49 | $file = $this->file_id; 50 | }elseif(empty($file)){ 51 | return FALSE; 52 | } 53 | 54 | $this->parent 55 | ->_push_method("deleteStickerFromSet") 56 | ->_push('sticker', $file) 57 | ->send(); 58 | } 59 | 60 | } 61 | 62 | ?> 63 | -------------------------------------------------------------------------------- /src/User.php: -------------------------------------------------------------------------------- 1 | $v){ 18 | $$k = $v; 19 | } 20 | } 21 | 22 | if($first_name instanceof Bot){ 23 | $this->bot = $first_name; 24 | $this->is_bot = TRUE; 25 | } 26 | 27 | $first_name = str_replace("\u{202e}", "", $first_name); 28 | $last_name = str_replace("\u{202e}", "", $last_name); 29 | 30 | $this->id = intval($id); 31 | $this->first_name = trim($first_name); 32 | $this->username = trim($username); 33 | $this->last_name = trim($last_name); 34 | $this->language_code = trim($language_code); 35 | $this->is_bot = (bool) $is_bot; 36 | 37 | /* if(!empty($this->username)){ 38 | $this->is_bot = (strtolower(substr($this->username, -3)) == "bot"); 39 | } */ 40 | 41 | return $this; 42 | } 43 | 44 | public function avatar($id = NULL){ 45 | // group or user, if not already get, get info 46 | // and save to self variable 47 | } 48 | 49 | public function info($bot = NULL){ 50 | if(!empty($this->bot) && empty($bot)){ $bot = $this->bot; } 51 | $send = new Sender($bot); 52 | $info = $send->get_chat($this->id); 53 | return $this->__construct($info); 54 | } 55 | 56 | public function link($text = NULL, $html = TRUE){ 57 | $url = "tg://user?id=" .$this->id; 58 | if($text === NULL){ return $url; } 59 | if($text === TRUE){ $text = strval($this); } 60 | if($html){ return '' .$text .''; } 61 | return '[' .$text .'](' .$url .')'; 62 | } 63 | 64 | public function __toString(){ 65 | return trim($this->first_name ." " .$this->last_name); 66 | } 67 | 68 | public function __get($k){ 69 | if(isset($this->$k)){ return $this->$k; } 70 | if(array_key_exists($k, $this->extra)){ return $this->extra[$k]; } 71 | return NULL; 72 | } 73 | 74 | public function __set($k, $v){ 75 | if(isset($this->$k)){ $this->$k = $v; } 76 | else{ $this->extra[$k] = $v; } 77 | } 78 | } 79 | 80 | ?> 81 | --------------------------------------------------------------------------------