1
0

AbstractProxy.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <?php declare(strict_types=1);
  2. /**
  3. * PrivateBin
  4. *
  5. * a zero-knowledge paste bin
  6. *
  7. * @link https://github.com/PrivateBin/PrivateBin
  8. * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  9. * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
  10. */
  11. namespace PrivateBin\Proxy;
  12. use JsonException;
  13. use PrivateBin\Configuration;
  14. use PrivateBin\Json;
  15. /**
  16. * AbstractProxy
  17. *
  18. * Forwards a URL for shortening and stores the result.
  19. */
  20. abstract class AbstractProxy
  21. {
  22. /**
  23. * error message
  24. *
  25. * @access private
  26. * @var string
  27. */
  28. private $_error = '';
  29. /**
  30. * proxy URL
  31. *
  32. * @access protected
  33. * @var string
  34. */
  35. protected $_proxyUrl = '';
  36. /**
  37. * shortened URL
  38. *
  39. * @access private
  40. * @var string
  41. */
  42. private $_url = '';
  43. /**
  44. * constructor
  45. *
  46. * initializes and runs the proxy class
  47. *
  48. * @access public
  49. * @param Configuration $conf
  50. * @param string $link
  51. */
  52. public function __construct(Configuration $conf, string $link)
  53. {
  54. if (!filter_var($link, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED | FILTER_FLAG_QUERY_REQUIRED)) {
  55. $this->_error = 'Invalid URL given.';
  56. return;
  57. }
  58. if (!str_starts_with($link, $conf->getKey('basepath') . '?') ||
  59. parse_url($link, PHP_URL_HOST) !== parse_url($conf->getKey('basepath'), PHP_URL_HOST)
  60. ) {
  61. $this->_error = 'Trying to shorten a URL that isn\'t pointing at our instance.';
  62. return;
  63. }
  64. $this->_proxyUrl = $this->_getProxyUrl($conf);
  65. if (empty($this->_proxyUrl)) {
  66. $this->_error = 'Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.';
  67. $this->logErrorWithClassName($this->_error);
  68. return;
  69. }
  70. $data = file_get_contents($this->_proxyUrl, false,
  71. stream_context_create(
  72. [
  73. 'http' => $this->_getProxyPayload($conf, $link),
  74. ]
  75. )
  76. );
  77. if ($data === false) {
  78. $http_response_header = $http_response_header ?? [];
  79. $statusCode = '';
  80. if (!empty($http_response_header) && preg_match('/HTTP\/\d+\.\d+\s+(\d+)/', $http_response_header[0], $matches)) {
  81. $statusCode = $matches[1];
  82. }
  83. $this->_error = 'Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.';
  84. $this->logErrorWithClassName($this->_error . ' Status code: ' . $statusCode);
  85. return;
  86. }
  87. try {
  88. $jsonData = Json::decode($data);
  89. } catch (JsonException $e) {
  90. $this->_error = 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.';
  91. $this->logErrorWithClassName('Error calling proxy: ' . $e->getMessage());
  92. return;
  93. }
  94. $url = $this->_extractShortUrl($jsonData);
  95. if ($url === null || empty($url)) {
  96. $this->_error = 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.';
  97. $this->logErrorWithClassName('Error calling proxy: ' . $data);
  98. } else {
  99. $this->_url = $url;
  100. }
  101. }
  102. private function logErrorWithClassName(string $error)
  103. {
  104. error_log('[' . get_class($this) . '] ' . $error);
  105. }
  106. /**
  107. * Returns the (untranslated) error message
  108. *
  109. * @access public
  110. * @return string
  111. */
  112. public function getError()
  113. {
  114. return $this->_error;
  115. }
  116. /**
  117. * Returns the shortened URL
  118. *
  119. * @access public
  120. * @return string
  121. */
  122. public function getUrl()
  123. {
  124. return $this->_url;
  125. }
  126. /**
  127. * Returns true if any error has occurred
  128. *
  129. * @access public
  130. * @return bool
  131. */
  132. public function isError()
  133. {
  134. return !empty($this->_error);
  135. }
  136. /**
  137. * Abstract method to get the payload to send to the URL shortener
  138. *
  139. * @access protected
  140. * @param Configuration $conf
  141. * @param string $link
  142. * @return array
  143. */
  144. abstract protected function _getProxyPayload(Configuration $conf, string $link): array;
  145. /**
  146. * Abstract method to extract the shortUrl from the response
  147. *
  148. * @param array $data
  149. * @return ?string
  150. */
  151. abstract protected function _extractShortUrl(array $data): ?string;
  152. /**
  153. * Abstract method to get the proxy URL
  154. *
  155. * @param Configuration $conf
  156. * @return string
  157. */
  158. abstract protected function _getProxyUrl(Configuration $conf): string;
  159. }