Files
MokoSuiteCross/source/packages/com_mokosuitecross/src/Helper/LinkShortenerHelper.php
T
Jonathan Miller 45afb1f0b1
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Universal: PR Check / Secret Scan (pull_request) Successful in 4s
Universal: Auto Version Bump / Version Bump (push) Successful in 9s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 33s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
feat(#159): add link shortening support (Bitly, Rebrandly, YOURLS) with {url_short} placeholder
Authored-by: Moko Consulting
2026-06-28 11:14:04 -05:00

173 lines
4.1 KiB
PHP

<?php
/**
* @package MokoSuiteCross
* @subpackage com_mokosuitecross
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
* SPDX-License-Identifier: GPL-3.0-or-later
*/
namespace Joomla\Component\MokoSuiteCross\Administrator\Helper;
defined('_JEXEC') or die;
use Joomla\CMS\Component\ComponentHelper;
/**
* Shortens URLs via Bitly, Rebrandly, or YOURLS.
*
* Returns the original URL on any failure so cross-posts are never broken.
*/
class LinkShortenerHelper
{
/**
* Shorten a URL using the configured provider.
*
* @param string $url The URL to shorten
*
* @return string Shortened URL, or the original on failure/disabled
*/
public static function shorten(string $url): string
{
$params = ComponentHelper::getParams('com_mokosuitecross');
$provider = $params->get('link_shortener', 'none');
if ($provider === 'none' || empty($url)) {
return $url;
}
$apiKey = $params->get('link_shortener_api_key', '');
switch ($provider) {
case 'bitly':
return self::shortenWithBitly($url, $apiKey);
case 'rebrandly':
return self::shortenWithRebrandly($url, $apiKey);
case 'yourls':
$apiUrl = $params->get('link_shortener_yourls_url', '');
$token = $params->get('link_shortener_yourls_token', '');
return self::shortenWithYourls($url, $apiUrl, $token);
default:
return $url;
}
}
/**
* Shorten via Bitly API v4.
*/
public static function shortenWithBitly(string $url, string $apiKey): string
{
if (empty($apiKey)) {
return $url;
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api-ssl.bitly.com/v4/shorten',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(['long_url' => $url]),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response === false || $httpCode < 200 || $httpCode >= 300) {
return $url;
}
$data = json_decode($response, true);
return $data['link'] ?? $url;
}
/**
* Shorten via Rebrandly API.
*/
public static function shortenWithRebrandly(string $url, string $apiKey, string $workspace = ''): string
{
if (empty($apiKey)) {
return $url;
}
$headers = [
'apikey: ' . $apiKey,
'Content-Type: application/json',
];
if (!empty($workspace)) {
$headers[] = 'workspace: ' . $workspace;
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.rebrandly.com/v1/links',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(['destination' => $url]),
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response === false || $httpCode < 200 || $httpCode >= 300) {
return $url;
}
$data = json_decode($response, true);
$short = $data['shortUrl'] ?? '';
return !empty($short) ? 'https://' . ltrim($short, 'https://') : $url;
}
/**
* Shorten via YOURLS API (self-hosted).
*/
public static function shortenWithYourls(string $url, string $apiUrl, string $signatureToken): string
{
if (empty($apiUrl) || empty($signatureToken)) {
return $url;
}
$endpoint = rtrim($apiUrl, '/') . '?' . http_build_query([
'action' => 'shorturl',
'format' => 'json',
'signature' => $signatureToken,
'url' => $url,
]);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response === false || $httpCode < 200 || $httpCode >= 300) {
return $url;
}
$data = json_decode($response, true);
return $data['shorturl'] ?? $url;
}
}