]> git.mxchange.org Git - friendica.git/blob - library/slinky.php
Merge branch 'master' of https://github.com/friendica/friendica
[friendica.git] / library / slinky.php
1 <?php
2 /*
3 Copyright (c) 2009, Beau Lebens
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without modification,
7 are permitted provided that the following conditions are met:
8
9  - Redistributions of source code must retain the above copyright notice, this 
10    list of conditions and the following disclaimer.
11  - Redistributions in binary form must reproduce the above copyright notice, 
12    this list of conditions and the following disclaimer in the documentation 
13    and/or other materials provided with the distribution.
14  - Neither the name of Dented Reality nor the names of the authors may be used 
15    to endorse or promote products derived from this software without specific 
16    prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND     ON
25 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28         
29 */
30
31 // Return options for Slinky_Service->url_get() and ->url_post()
32 define( 'SLINKY_BODY', 1 ); // Default
33 define( 'SLINKY_HEADERS', 2 ); // Not implemented yet
34 define( 'SLINKY_FINAL_URL', 3 ); // Default for lengthening URLs
35
36 // So that services may decide what to do with us
37 define( 'SLINKY_USER_AGENT', 'Slinky v1.0 +http://dentedreality.com.au/projects/slinky/' );
38
39 // How many seconds until remote requests should be cut?
40 define( 'SLINKY_TIMEOUT', 10 );
41
42 /**
43  * Slinky allows you to go back and forth between "long" and shortened URLs 
44  * using popular URL shortening services.
45  * 
46  * Slinky assumes you have cURL installed and working, and requires the JSON
47  * extension installed if you're working with a service that uses JSON.
48  * 
49  * Slinky will ONLY work with PHP5+
50  * 
51  * It supports some of the more popular services, with easy extensibility for
52  * adding your own relatively easily. It defaults to using TinyURL
53  * for shortening URLs. If you want to use some of the other services, you need
54  * to set some configuration options before actually shortening/lengthening
55  * URLs. I'd strongly suggest that you cache results using memcached, a local
56  * DB or whatever to avoid having to hit APIs etc every time you encounter a
57  * URL.
58  * 
59  * Slinky supports shortening, and auto-detection (for lengthening URLs) 
60  * using these services:
61  * - Bit.ly
62  * - Tr.im
63  * - TinyURL
64  * - Is.Gd
65  * - Fon.gs
66  * - Micurl.com
67  * - ur1.ca
68  * - Ptiturl
69  * - Tighturl
70  * - 2tu.us
71  * - Snipr / Snipurl / Snurl.com / Sn.im
72  * 
73  * 
74  * To use Slinky:
75  * 
76  * $slinky = new Slinky( 'http://dentedreality.com.au/' );
77  * - Creates a new Slinky instance, will default to using TinyURL for ->short();
78  * 
79  * $slinky = new Slinky( 'http://dentedreality.com.au', new Slinky_Bitly() );
80  * - Creates new Slinky, forces use of Bit.ly for ->short();
81  * 
82  * $slinky = new Slinky( 'http://dentedreality.com.au/' );
83  * echo $slinky->short();
84  * - echos the short version of http://dentedreality.com.au/ (default to TinyURL)
85  * 
86  * $slinky = new Slinky( 'http://tinyurl.com/jw5sh' );
87  * echo $slinky->long();
88  * - echos out the long version of http://tinyurl.com/jw5sh (which should be http://dentedreality.com.au/)
89  * 
90  * $slinky = new Slinky( 'http://dentedreality.com.au/' );
91  * echo $slinky->long();
92  * - Attempts to lengthen the URL, but will not auto-detect which service it is
93  *   so it will just output the original URL. Useful for always attempting to
94  *   lengthen any URL you come across (fails gracefully)
95  * 
96  * $slinky = new Slinky( 'http://dentedreality.com.au/' );
97  * $slinky->set_cascade( array( new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
98  * echo $slinky->short();
99  * - Uses the powerful cascade mode to make sure that we get a short URL from 
100  *   Tr.im, Is.Gd or TinyURL (in that order).
101  * 
102  * See specific service class definitions below for examples of how to use them,
103  * as some services allow (or require) additional properties before you can use
104  * them (for authentication etc).
105  * 
106  * To use a different service with Slinky, just create your own class and
107  * extend Slinky_Service(). Make sure you implement url_is_short(), url_is_long(),
108  * make_short() and make_long(). If you need to GET or POST a URL, you can use
109  * ->url_get() and ->url_post(), which your class will have inherited.
110 **/
111 class Slinky {
112         var $url     = false;
113         var $service = false;
114         var $cascade = false;
115         
116         function __construct( $url = false, $service = false ) {
117                 $this->url     = $url;
118                 $this->service = $service;
119         }
120         
121         /**
122          * Specify which URL Service to use
123          *
124          * @param Slinky_Service $service Packaged or custom Service object
125          * @return void
126          */
127         public function set_service( $service = false ) {
128                 if ( is_object( $service ) ) {
129                         $this->service = $service;
130                 }
131         }
132         
133         /**
134          * If you pass an array of Slinky_Service objects to this method, they will
135          * be used in order to try to get a short URL, so if one fails, it will
136          * try the next and so on, until it gets a valid short URL, or it runs
137          * out of options.
138          * 
139          * @param array $services List of Slinky_Service objects as an array
140         **/
141         public function set_cascade( $services = false ) {
142                 if ( !$services || !is_array( $services ) )
143                         return false;
144                 
145                 $this->cascade = $services;
146         }
147         
148         /**
149          * Guess the URL service to use from known domains of short URLs
150          *
151          * @param string $url 
152          */
153         public function set_service_from_url( $url = false ) {
154                 if ( !$url )
155                         $url = $this->url;
156
157                 $host = parse_url( $url, PHP_URL_HOST );
158                 switch ( str_replace( 'www.', '', $host ) ) {
159                         case 'bit.ly':
160                                 if ( class_exists( 'Slinky_Bitly' ) ) {
161                                         $this->service = new Slinky_Bitly();
162                                         break;
163                                 }
164                         case 'tr.im':
165                                 if ( class_exists( 'Slinky_Trim' ) ) {
166                                         $this->service = new Slinky_Trim();
167                                         break;
168                                 }
169                         case 'tinyurl.com':
170                                 if ( class_exists( 'Slinky_TinyURL' ) ) {
171                                         $this->service = new Slinky_TinyURL();
172                                         break;
173                                 }
174                         case 'is.gd':
175                                 if ( class_exists( 'Slinky_IsGd' ) ) {
176                                         $this->service = new Slinky_IsGd();
177                                         break;
178                                 }
179                         case 'fon.gs':
180                                 if ( class_exists( 'Slinky_Fongs' ) ) {
181                                         $this->service = new Slinky_Fongs();
182                                         break;
183                                 }
184                         case $this->get( 'yourls-url' ):
185                                 if ( class_exists( 'Slinky_YourLS' ) ) {
186                                         $this->service = new Slinky_YourLS();
187                                         break;
188                                 }
189                         case 'micurl.com':
190                                 if ( class_exists( 'Slinky_Micurl' ) ) {
191                                         $this->service = new Slinky_Micurl();
192                                         break;
193                                 }
194                         case 'ur1.ca':
195                                 if ( class_exists( 'Slinky_Ur1ca' ) ) {
196                                         $this->service = new Slinky_Ur1ca();
197                                         break;
198                                 }
199                         case 'ptiturl.com':
200                                 if ( class_exists( 'Slinky_PtitURL' ) ) {
201                                         $this->service = new Slinky_PtitURL();
202                                         break;
203                                 }
204                         case 'tighturl.com':
205                         case '2tu.us':
206                                 if ( class_exists( 'Slinky_TightURL' ) ) {
207                                         $this->service = new Slinky_TightURL();
208                                         break;
209                                 }
210                         case 'snipr.com':
211                         case 'snipurl.com':
212                         case 'snurl.com':
213                         case 'sn.im':
214                                 if ( class_exists( 'Slinky_Snipr' ) ) {
215                                         $this->service = new Slinky_Snipr();
216                                         break;
217                                 }
218                         default:
219                                 $this->service = new Slinky_Default();
220                                 break;
221                 }
222         }
223         
224         /**
225          * Take a long URL and make it short. Will avoid "re-shortening" a URL if it
226          * already seems to be short.
227          *
228          * @param string $url Optional URL to shorten, otherwise use $this->url
229          * @return The short version of the URL
230          */
231         public function short( $url = false ) {
232                 if ( $url )
233                         $this->url = $url;
234                         
235                 if ( !$this->service )
236                         $this->set_service( new Slinky_TinyURL() ); // Defaults to tinyurl because it doesn't require any configuration
237                 
238                 if ( !$this->cascade )
239                         $this->cascade = array( $this->service ); // Use a single service in cascade mode
240                 
241                 foreach ( $this->cascade as $service ) {
242                         if ( $service->url_is_short( $this->url ) )
243                                 return trim( $this->url ); // Identified as already short, using this service
244
245                         $response = trim( $service->make_short( $this->url ) );
246                         if ( $response && $this->url != $response )
247                                 return trim( $response );
248                 }
249                 
250                 return $this->url; // If all else fails, just send back the URL we already know about
251         }
252         
253         /**
254          * Take a short URL and make it long ("resolve" it).
255          *
256          * @param string $url The short URL
257          * @return A long URL
258          */
259         public function long( $url = false ) {
260                 if ( $url )
261                         $this->url = $url;
262                         
263                 if ( !$this->service )
264                         $this->set_service_from_url();
265                 
266                 if ( $this->service->url_is_long( $this->url ) )
267                         return trim( $this->url );
268                 
269                 return trim( $this->service->make_long( $this->url ) );
270         }
271 }
272
273 /**
274  * Use this class to create a Service implementation for your own URL 
275  * shortening service. Extend the class and customize methods to suit your 
276  * service. Note that it is an "abstract" class, so there are certain methods 
277  * which you *must* define.
278 **/
279 abstract class Slinky_Service {
280         
281         /**
282          * Determine, based on the input URL, if it's already a short URL, from
283          * this particular service. e.g. a Bit.ly URL contains "bit.ly/"
284         **/
285         abstract function url_is_short( $url );
286         
287         /**
288          * Determine if this is a "long" URL (just means it hasn't been shortened)
289          * already. e.g. a no-Bit.ly URL would NOT contain "bit.ly/"
290         **/
291         abstract function url_is_long( $url );
292         
293         /**
294          * Handle taking the $url and converting it to a short URL via whatever
295          * means is provided at the remote service.
296         **/
297         abstract function make_short( $url );
298         
299         /**
300          * Return the long/expanded version of a URL via any API means available
301          * from this service. As a fallback, you might
302          * consider just following the URL and using SLINKY_FINAL_URL as the 
303          * return method from a $this->url_get() call to find out.
304          * 
305          * This one is optional for Services extending this class, if they don't
306          * then the following implementation will work on most services anyway.
307         **/
308         public function make_long( $url ) {
309                 return $this->url_get( $url, SLINKY_FINAL_URL );
310         }
311         
312         /**
313          * Method for getting properties that you might need during the process
314          * of shortening/lengthening a URL (e.g. auth credentials)
315         **/
316         public function get( $prop ) {
317                 if ( empty( $this->$prop ) )
318                         return null;
319                         
320                 return $this->$prop;
321         }
322         
323         /**
324          * Method for setting properties that you might need during the process
325          * of shortening/lengthening a URL (e.g. auth credentials)
326         **/
327         public function set( $prop, $val ) {
328                 $this->$prop = $val;
329         }
330         
331         /**
332          * Internal helper for performing a GET request on a remote URL.
333          * 
334          * @param string $url The URL to GET
335          * @param const $return The return method [ SLINKY_BODY | SLINKY_FINAL_URL | SLINKY_HEADERS ]
336          * @return Mixed, based on the $return var passed in.
337         **/
338         protected function url_get( $url, $return = SLINKY_BODY ) {
339                 $ch = curl_init( $url );
340                 curl_setopt( $ch, CURLOPT_USERAGENT, SLINKY_USER_AGENT );
341                 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );                  // Don't stress about SSL validity
342                 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );                  // Return the response, don't output it
343                 curl_setopt( $ch, CURLOPT_TIMEOUT, SLINKY_TIMEOUT );    // Limit how long we'll wait for a response
344                 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );                  // Allow following of redirections
345                 $r  = curl_exec( $ch );
346                 if ( curl_errno( $ch ) ) {
347                         return false;
348                 }
349                 
350                 // Return whatever we were asked for
351                 if ( SLINKY_FINAL_URL == $return )
352                         return curl_getinfo( $ch, CURLINFO_EFFECTIVE_URL );
353                 else if ( SLINKY_BODY == $return )
354                         return $r;
355                 
356                 return false;
357         }
358         
359         /**
360          * Internal helper for performing a POST request on a remote URL.
361          * 
362          * @param string $url The URL to POST to
363          * @param array $payload Array containing name/value pairs of the parameters to POST
364          * @param const $return The return method [ SLINKY_BODY | SLINKY_FINAL_URL | SLINKY_HEADERS ]
365          * @return Mixed, based on the $return var passed in.
366         **/
367         protected function url_post( $url, $payload = array(), $return = SLINKY_BODY ) {
368                 $ch = curl_init( $url );
369                 curl_setopt( $ch, CURLOPT_POST, true );
370                 curl_setopt( $ch, CURLOPT_POSTFIELDS, (array) $payload );
371                 curl_setopt( $ch, CURLOPT_USERAGENT, SLINKY_USER_AGENT );
372                 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );                  // Don't stress about SSL validity
373                 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );                  // Return the response, don't output it
374                 curl_setopt( $ch, CURLOPT_TIMEOUT, SLINKY_TIMEOUT );    // Limit how long we'll wait for a response
375                 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );                  // Allow following of redirections
376                 $r  = curl_exec( $ch );
377                 if ( curl_errno( $ch ) ) {
378                         return false;
379                 }
380                 
381                 // Return whatever we were asked for
382                 if ( SLINKY_FINAL_URL == $return )
383                         return curl_getinfo( $ch, CURLINFO_EFFECTIVE_URL );
384                 else if ( SLINKY_BODY == $return )
385                         return $r;
386                 
387                 return false;
388         }
389 }
390
391 // This default service is used in cases when you try to do something based
392 // on auto-detection, but we can't detect anything. It will also resolve URLs
393 // to their "long" version by following all redirects.
394 class Slinky_Default extends Slinky_Service {
395         function url_is_short( $url ) {
396                 return false;
397         }
398         
399         function url_is_long( $url ) {
400                 return false;
401         }
402         
403         function make_short( $url ) {
404                 return $url;
405         }
406 }
407
408 // Implementation of TinyURL as a Slinky Service
409 class Slinky_TinyURL extends Slinky_Service {
410         function url_is_short( $url ) {
411                 return stristr( $url, 'tinyurl.com/' );
412         }
413         
414         function url_is_long( $url ) {
415                 return !stristr( $url, 'tinyurl.com/' );
416         }
417         
418         function make_short( $url ) {
419                 return $this->url_get( 'http://tinyurl.com/api-create.php?url=' . urlencode( $url ) );
420         }
421         
422         function make_long( $url ) {
423                 $bits = parse_url( $url );
424                 $result = $this->url_get( 'http://tinyurl.com/preview.php?num=' . substr( $bits['path'], 1 ) );
425                 if ( preg_match('/<a id="redirecturl" href="([^"]+)">/is', $result, $matches ) )
426                         return $matches[1];
427                 else
428                         return $url;
429         }
430 }
431
432 // Implementation of Bit.ly as a Slinky Service
433 /*
434 To use Bit.ly, you MUST set your login and apiKey for the service first, e.g.
435
436 $bitly = new Slinky_Bitly();
437 $bitly->set( 'login', 'bitly_login' );
438 $bitly->set( 'apiKey', 'bitly_apiKey' );
439
440 $slinky = new Slinky( $url, $bitly );
441 echo $slinky->short();
442
443 You could also do this if the URL was already a bit.ly URL and you 
444 were going to make it longer, since Bitly is supported for auto-detection:
445
446 $slinky = new Slinky( $url );
447 $slinky->set_service_from_url();
448 $slinky->service->set( 'login', 'bitly_login' );
449 $slinky->service->set( 'apiKey', 'bitly_apiKey' );
450 echo $slinky->long();
451
452 */
453 class Slinky_Bitly extends Slinky_Service {
454         function url_is_short( $url ) {
455                 return stristr( $url, 'bit.ly/' );
456         }
457         
458         function url_is_long( $url ) {
459                 return !stristr( $url, 'bit.ly/' );
460         }
461         
462         function make_short( $url ) {
463                 // Can't do anything unless these 2 properties are set first
464                 if ( !$this->get( 'login' ) || !$this->get( 'apiKey' ) )
465                         return $url;
466                 
467                 $result = $this->url_post( 'http://api.bit.ly/shorten?version=2.0.1&format=json&login=' . $this->get( 'login' ) . '&apiKey=' . $this->get( 'apiKey' ) . '&longUrl=' . urlencode( $url ) );
468                 $result = json_decode( $result );
469                 if ( !$result->errorCode ) {
470                         foreach ( $result->results as $detail ) {
471                                 return $detail->shortUrl;
472                         }
473                 } else {
474                         return false;
475                 }
476         }
477         
478         function make_long( $url ) {
479                 // Can't do anything unless these 2 properties are set first
480                 if ( !$this->get( 'login' ) || !$this->get( 'apiKey' ) )
481                         return $url;
482                 
483                 $result = $this->url_post( 'http://api.bit.ly/expand?version=2.0.1&format=json&login=' . $this->get( 'login' ) . '&apiKey=' . $this->get( 'apiKey' ) . '&shortUrl=' . urlencode( $url ) );
484                 $result = json_decode( $result );
485                 if ( !$result->errorCode ) {
486                         foreach ( $result->results as $detail ) {
487                                 return $detail->longUrl;
488                         }
489                 } else {
490                         return false;
491                 }
492         }
493 }
494
495 // Implementation of Tr.im as a Slinky Service
496 /*
497 When using Tr.im, you MAY optionally set your username and password to tie 
498 URLs to your account, e.g.
499
500 $trim = new Slinky_Trim();
501 $trim->set( 'username', 'trim_username' );
502 $trim->set( 'password', 'trim_password' );
503
504 $slinky = new Slinky( $url, $trim );
505 echo $slinky->short();
506
507 You could also do this if the URL was already a tr.im URL and you 
508 were going to make it longer, since Tr.im is supported for auto-detection:
509
510 $slinky = new Slinky( $url );
511 $slinky->set_service_from_url();
512 echo $slinky->long();
513
514 */
515 class Slinky_Trim extends Slinky_Service {
516         function url_is_short( $url ) {
517                 return stristr( $url, 'tr.im/' );
518         }
519         
520         function url_is_long( $url ) {
521                 return !stristr( $url, 'tr.im/' );
522         }
523         
524         function make_short( $url ) {
525                 $url = 'http://api.tr.im/api/trim_simple?url=' . urlencode( $url );
526
527                 if ( $this->get( 'username' ) && $this->get( 'password' ) )
528                         $url .= '&username=' . urlencode( $this->get( 'username' ) ) . '&password=' . urlencode( $this->get( 'password' ) );
529                 
530                 return $this->url_get( $url );
531         }
532         
533         function make_long( $url ) {
534                 $bits = parse_url( $url );
535                 $result = $this->url_get( 'http://api.tr.im/api/trim_destination.json?trimpath=' . substr( $bits['path'], 1 ) );
536                 $result = json_decode($result);
537                 if ( 'OK' == $result->status->result )
538                         return $result->destination;
539                 else
540                         return $url;
541         }
542 }
543
544 // Implementation of Is.Gd as a Slinky Service
545 class Slinky_IsGd extends Slinky_Service {
546         function url_is_short( $url ) {
547                 return stristr( $url, 'is.gd/' );
548         }
549         
550         function url_is_long( $url ) {
551                 return !stristr( $url, 'is.gd/' );
552         }
553         
554         function make_short( $url ) {
555                 $response = $this->url_get( 'http://is.gd/api.php?longurl=' . urlencode( $url ) );
556                 if ( 'error' == substr( strtolower( $response ), 0, 5 ) )
557                         return false;
558                 else
559                         return $response;
560         }
561 }
562
563 // Fon.gs
564 class Slinky_Fongs extends Slinky_Service {
565         function url_is_short( $url ) {
566                 return stristr( $url, 'fon.gs/' );
567         }
568         
569         function url_is_long( $url ) {
570                 return !stristr( $url, 'fon.gs/' );
571         }
572         
573         function make_short( $url ) {
574                 $response = $this->url_get( 'http://fon.gs/create.php?url=' . urlencode( $url ) );
575                 if ( 'OK:' == substr( $response, 0, 3 ) )
576                         return str_replace( 'OK: ', '', $response );
577                 else
578                         return $url;
579         }
580 }
581
582 // yourls
583 class Slinky_YourLS extends Slinky_Service {
584         function url_is_short( $url ) {
585         return stristr( $url, 'shit.li/' );
586     }
587     
588         function url_is_long( $url ) {
589         return !stristr( $url, 'shit.li/' );
590     }
591     
592         function make_short( $url ) {
593                 echo $this->get( 'username' );
594                 $use_ssl = $this->get( 'ssl' );
595                 if ( $use_ssl )
596                         $use_ssl  = 's';
597                 else
598                         $use_ssl = '';
599                 $result = $this->url_get( 'http'. $use_ssl . '://' . $this->get( 'yourls-url' ) . '/yourls-api.php?username=' . $this->get( 'username' )  . '&password=' . $this->get( 'password' ) . '&action=shorturl&format=simple&url=' . urlencode( $url ) );
600                 if ( 1 != $result && 2 != $result )
601                         return $result;
602                 else
603                         return $url;
604         }
605 }
606
607 // Micu.rl
608 class Slinky_Micurl extends Slinky_Service {
609         function url_is_short( $url ) {
610                 return stristr( $url, 'micurl.com/' );
611         }
612         
613         function url_is_long( $url ) {
614                 return !stristr( $url, 'micurl.com/' );
615         }
616         
617         function make_short( $url ) {
618                 $result = $this->url_get( 'http://micurl.com/api.php?url=' . urlencode( $url ) );
619                 if ( 1 != $result && 2 != $result )
620                         return 'http://micurl.com/' . $result;
621                 else
622                         return $url;
623         }
624 }
625
626 // ur1.ca
627 class Slinky_Ur1ca extends Slinky_Service {
628         function url_is_short( $url ) {
629                 return stristr( $url, 'ur1.ca/' );
630         }
631         
632         function url_is_long( $url ) {
633                 return !stristr( $url, 'ur1.ca/' );
634         }
635         
636         function make_short( $url ) {
637                 $result = $this->url_post( 'http://ur1.ca/', array( 'longurl' => $url ) );
638                 if ( preg_match( '/<p class="success">Your ur1 is: <a href="([^"]+)">/', $result, $matches ) )
639                         return $matches[1];
640                 else
641                         return $url;
642         }
643 }
644
645 // PtitURL.com
646 class Slinky_PtitURL extends Slinky_Service {
647         function url_is_short( $url ) {
648                 return stristr( $url, 'ptiturl.com/' );
649         }
650         
651         function url_is_long( $url ) {
652                 return !stristr( $url, 'ptiturl.com/' );
653         }
654         
655         function make_short( $url ) {
656                 $result = $this->url_get( 'http://ptiturl.com/index.php?creer=oui&url=' . urlencode( $url ) );
657                 if ( preg_match( '/<pre><a href=\'?([^\'>]+)\'?>/', $result, $matches ) )
658                         return $matches[1];
659                 else
660                         return $url;
661         }
662 }
663
664 // Tighturl.com
665 class Slinky_TightURL extends Slinky_Service {
666         function url_is_short( $url ) {
667                 return stristr( $url, 'tighturl.com/' )
668                                 || stristr( $url, '2tu.us/' );
669         }
670         
671         function url_is_long( $url ) {
672                 return !stristr( $url, 'tighturl.com/' )
673                                 && !stristr( $url, '2tu.us/' );
674         }
675         
676         function make_short( $url ) {
677                 $response = $this->url_get( 'http://tighturl.com/?save=y&url=' . urlencode( $url ) );
678                 if ( preg_match( '/Your tight URL is: <code><a href=\'([^\']+)\' target=\'_blank\'>/', $response, $matches ) ) {
679                         return $matches[1];
680                 } else {
681                         return $url;
682                 }
683         }
684 }
685
686 // Snipr for Slinky
687 /*
688 To use Snipr, you MUST set your user_id and API (key) for the service first, e.g.
689
690 $snipr = new Slinky_Snipr();
691 $snipr->set( 'user_id', 'Snipr User ID' );
692 $snipr->set( 'API', 'Snipr API Key' );
693
694 $slinky = new Slinky( $url, $snipr );
695 echo $slinky->short();
696
697 NOTE: Snipr requires the SimpleXML extension to be installed for lengthening URLs
698 */
699 class Slinky_Snipr extends Slinky_Service {
700         // Snipurl, Snurl, Snipr, Sn.im
701         function url_is_short( $url ) {
702                 return stristr( $url, 'snipr.com/' ) || stristr( $url, 'snipurl.com/' ) || stristr( $url, 'snurl.com/' ) || stristr( $url, 'sn.im/' );
703         }
704         
705         function url_is_long( $url ) {
706                 return !stristr( $url, 'snipr.com/' ) || !stristr( $url, 'snipurl.com/' ) || !stristr( $url, 'snurl.com/' ) || !stristr( $url, 'sn.im/' );
707         }
708         
709         function make_short( $url ) {
710                 if ( !$this->get( 'user_id' ) || !$this->get( 'API' ) )
711                         return $url;
712                 
713                 $response = $this->url_post( 'http://snipr.com/site/getsnip', array( 'sniplink' => urlencode( $url ), 'snipuser' => $this->get( 'user_id'), 'snipapi' => $this->get( 'API' ), 'snipformat' => 'simple' ) );
714                 if ( 'ERROR' != substr( $response, 0, 5 ) )
715                         return $response;
716                 else
717                         return $url;
718         }
719 }
720
721 // If you're testing things out, http://dentedreality.com.au/ should convert to:
722 // - http://tinyurl.com/jw5sh
723 // - http://bit.ly/hEkAD
724 // - http://tr.im/sk1H
725 // - http://is.gd/1yJ81
726 // - http://fon.gs/tc1p8c
727 // - http://micurl.com/qen3uub
728 // - http://ur1.ca/7dcd
729 // - http://ptiturl.com/?id=bac8fb
730 // - http://tighturl.com/kgd
731 // - http://snipr.com/nbbw3
732 // 
733 // $slinky = new Slinky( 'http://dentedreality.com.au/' );
734 // echo $slinky->short();