├── 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 |
--------------------------------------------------------------------------------