| 1 |
<?php |
| 2 |
/* |
| 3 |
* License: GPLv3 |
| 4 |
* License URI: https://www.gnu.org/licenses/gpl.txt |
| 5 |
* Copyright 2019-2026 Jean-Sebastien Morisset (https://surniaulula.com/) |
| 6 |
*/ |
| 7 |
|
| 8 |
if ( ! defined( 'ABSPATH' ) ) { |
| 9 |
|
| 10 |
die( 'These aren\'t the droids you\'re looking for.' ); |
| 11 |
} |
| 12 |
|
| 13 |
if ( ! class_exists( 'SucomBitly' ) ) { |
| 14 |
|
| 15 |
class SucomBitly { |
| 16 |
|
| 17 |
private $access_token = ''; |
| 18 |
private $domain = ''; |
| 19 |
private $group_guid = ''; |
| 20 |
private $curl_connect_timeout = 5; // The number of seconds to wait while trying to connect. Use 0 to wait indefinitely. |
| 21 |
private $curl_timeout = 15; // The maximum number of seconds to allow cURL functions to execute. |
| 22 |
private $curl_max_redirs = 10; // The maximum amount of HTTP redirections to follow. |
| 23 |
|
| 24 |
private static $groups_api_url = 'https://api-ssl.bitly.com/v4/groups'; |
| 25 |
private static $shorten_api_url = 'https://api-ssl.bitly.com/v4/shorten'; |
| 26 |
|
| 27 |
public function __construct( $access_token, $domain = '', $group_name = '' ) { |
| 28 |
|
| 29 |
$this->access_token = $access_token; |
| 30 |
$this->domain = $domain; |
| 31 |
$this->group_guid = $this->get_group_guid( $group_name ); |
| 32 |
} |
| 33 |
|
| 34 |
public function get_group_guid( $group_name = '' ) { |
| 35 |
|
| 36 |
if ( '' === $group_name ) { |
| 37 |
|
| 38 |
return ''; |
| 39 |
} |
| 40 |
|
| 41 |
$resp_data = $this->api_call( self::$groups_api_url ); |
| 42 |
|
| 43 |
try { |
| 44 |
|
| 45 |
if ( is_array( $resp_data->groups ) ) { |
| 46 |
|
| 47 |
foreach ( $resp_data->groups as $group ) { |
| 48 |
|
| 49 |
if ( ! empty( $group->guid ) ) { // Just in case. |
| 50 |
|
| 51 |
if ( $group->name === $group_name ) { |
| 52 |
|
| 53 |
return $group->guid; // Return guid for the group name. |
| 54 |
} |
| 55 |
} |
| 56 |
} |
| 57 |
|
| 58 |
$group_msg = sprintf( __( 'Group name "%s" not found in the Bitly API response data.', 'wpsso' ), $group_name ); |
| 59 |
|
| 60 |
$except_msg = sprintf( __( '%1$s shortener API error: %2$s', 'wpsso' ), 'Bitly', $group_msg ); |
| 61 |
|
| 62 |
throw new WpssoErrorException( $except_msg ); |
| 63 |
|
| 64 |
} else { |
| 65 |
|
| 66 |
$group_msg = __( 'Groups property missing from the Bitly API response data.', 'wpsso' ); |
| 67 |
|
| 68 |
$except_msg = sprintf( __( '%1$s shortener API error: %2$s', 'wpsso' ), 'Bitly', $group_msg ); |
| 69 |
|
| 70 |
throw new WpssoErrorException( $except_msg ); |
| 71 |
} |
| 72 |
|
| 73 |
} catch ( WpssoErrorException $e ) { |
| 74 |
|
| 75 |
return $e->errorMessage( $ret = false ); |
| 76 |
} |
| 77 |
|
| 78 |
return false; |
| 79 |
} |
| 80 |
|
| 81 |
public function shorten( $long_url ) { |
| 82 |
|
| 83 |
if ( empty( $long_url ) ) { |
| 84 |
|
| 85 |
return false; // Nothing to shorten. |
| 86 |
} |
| 87 |
|
| 88 |
$api_data = array( |
| 89 |
'long_url' => (string) $long_url, |
| 90 |
); |
| 91 |
|
| 92 |
if ( ! empty( $this->domain ) ) { |
| 93 |
|
| 94 |
$api_data[ 'domain' ] = (string) $this->domain; |
| 95 |
} |
| 96 |
|
| 97 |
if ( ! empty( $this->group_guid ) ) { |
| 98 |
|
| 99 |
$api_data[ 'group_guid' ] = (string) $this->group_guid; |
| 100 |
} |
| 101 |
|
| 102 |
$resp_data = $this->api_call( self::$shorten_api_url, $api_data ); |
| 103 |
|
| 104 |
try { |
| 105 |
|
| 106 |
if ( empty( $resp_data->link ) ) { |
| 107 |
|
| 108 |
$url_msg = __( 'Link property value is empty.', 'wpsso' ); |
| 109 |
|
| 110 |
$except_msg = sprintf( __( '%1$s shortener API error: %2$s', 'wpsso' ), 'Bitly', $url_msg ); |
| 111 |
|
| 112 |
throw new WpssoErrorException( $except_msg ); |
| 113 |
|
| 114 |
} else { |
| 115 |
|
| 116 |
return $resp_data->link; |
| 117 |
} |
| 118 |
|
| 119 |
} catch ( WpssoErrorException $e ) { |
| 120 |
|
| 121 |
return $e->errorMessage(); |
| 122 |
} |
| 123 |
|
| 124 |
return false; |
| 125 |
} |
| 126 |
|
| 127 |
private function api_call( $api_url, $api_data = array() ) { |
| 128 |
|
| 129 |
$api_data_enc = wp_json_encode( $api_data ); |
| 130 |
|
| 131 |
$ch = curl_init(); |
| 132 |
|
| 133 |
$curl_headers = array( |
| 134 |
'Content-Type: application/json', |
| 135 |
'Authorization: Bearer ' . $this->access_token, |
| 136 |
'Accept: application/json', |
| 137 |
'Expect:', |
| 138 |
); |
| 139 |
|
| 140 |
if ( ! empty( $api_data ) ) { |
| 141 |
|
| 142 |
$curl_headers[] = 'Content-Length: ' . strlen( $api_data_enc ); |
| 143 |
|
| 144 |
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'POST' ); |
| 145 |
curl_setopt( $ch, CURLOPT_POSTFIELDS, $api_data_enc ); |
| 146 |
} |
| 147 |
|
| 148 |
curl_setopt( $ch, CURLOPT_URL, $api_url ); |
| 149 |
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); |
| 150 |
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $this->curl_connect_timeout ); |
| 151 |
curl_setopt( $ch, CURLOPT_TIMEOUT, $this->curl_timeout ); |
| 152 |
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 1 ); |
| 153 |
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 ); |
| 154 |
curl_setopt( $ch, CURLOPT_HTTPHEADER, $curl_headers ); |
| 155 |
|
| 156 |
$response = curl_exec( $ch ); |
| 157 |
$curl_errnum = curl_errno( $ch ); |
| 158 |
$curl_errmsg = curl_error( $ch ); // See https://curl.se/libcurl/c/libcurl-errors.html. |
| 159 |
$ssl_verify = (int) curl_getinfo( $ch, CURLINFO_SSL_VERIFYRESULT ); // See https://www.php.net/manual/en/function.curl-getinfo.php. |
| 160 |
$http_code = (int) curl_getinfo( $ch, CURLINFO_HTTP_CODE ); |
| 161 |
|
| 162 |
curl_close( $ch ); |
| 163 |
|
| 164 |
$http_success_codes = array( 200, 201 ); |
| 165 |
|
| 166 |
try { |
| 167 |
|
| 168 |
if ( ! empty( $curl_errnum ) ) { |
| 169 |
|
| 170 |
$except_msg = sprintf( __( '%1$s shortener API error: %2$s', 'wpsso' ), 'Bitly', $curl_errnum . ' ' . $curl_errmsg ); |
| 171 |
|
| 172 |
throw new WpssoErrorException( $except_msg ); |
| 173 |
|
| 174 |
} elseif ( ! in_array( $http_code, $http_success_codes ) ) { |
| 175 |
|
| 176 |
$resp_data = json_decode( $response, $assoc = false ); |
| 177 |
|
| 178 |
$json_error = trim( ( isset( $resp_data->message ) ? $resp_data->message : '' ) . ' ' . |
| 179 |
( isset( $resp_data->description ) ? $resp_data->description : '' ) ); |
| 180 |
|
| 181 |
if ( ! empty( $json_error ) ) { |
| 182 |
|
| 183 |
$except_msg = sprintf( __( '%1$s shortener API error: %2$s', 'wpsso' ), 'Bitly', $json_error ); |
| 184 |
|
| 185 |
throw new WpssoErrorException( $except_msg ); |
| 186 |
|
| 187 |
} else { |
| 188 |
|
| 189 |
$except_msg = sprintf( __( '%1$s shortener API error: %2$s', 'wpsso' ), 'Bitly', '' ); |
| 190 |
|
| 191 |
throw new WpssoErrorException( $except_msg, $http_code ); |
| 192 |
} |
| 193 |
|
| 194 |
} else { |
| 195 |
|
| 196 |
$resp_data = json_decode( $response, $assoc = false ); |
| 197 |
|
| 198 |
if ( null === $resp_data ) { |
| 199 |
|
| 200 |
$json_msg = sprintf( __( 'JSON response decode error code %d.', 'wpsso' ), json_last_error() ); |
| 201 |
|
| 202 |
$except_msg = sprintf( __( '%1$s shortener API error: %2$s', 'wpsso' ), 'Bitly', $json_msg ); |
| 203 |
|
| 204 |
throw new WpssoErrorException( $except_msg ); |
| 205 |
|
| 206 |
} else return $resp_data; |
| 207 |
} |
| 208 |
|
| 209 |
} catch ( WpssoErrorException $e ) { |
| 210 |
|
| 211 |
return $e->errorMessage(); |
| 212 |
} |
| 213 |
|
| 214 |
return false; |
| 215 |
} |
| 216 |
} |
| 217 |
} |
| 218 |
|