File: /home/nassaugo/public_html/wp-content/plugins/git-updater/src/Git_Updater/Traits/API_Common.php
<?php
/**
* Git Updater
*
* @author Andy Fragen
* @license MIT
* @link https://github.com/afragen/git-updater
* @package git-updater
*/
namespace Fragen\Git_Updater\Traits;
use Fragen\Git_Updater\Readme_Parser;
use Parsedown;
use stdClass;
/**
* Trait API_Common
*/
trait API_Common {
/**
* Holds loose class method name.
*
* @var null
*/
protected static $method;
/**
* Decode API responses that are base64 encoded.
*
* @param string $git Name of API, eg 'github'.
* @param mixed $response API response.
* @return mixed $response
*/
private function decode_response( $git, $response ) {
if ( 'github' === $git ) {
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
$response = isset( $response->content ) ? base64_decode( $response->content ) : $response;
}
/**
* Filter the API decode response.
*
* @param mixed $response API response.
* @param string $git Git host.
*/
return apply_filters( 'gu_decode_response', $response, $git );
}
/**
* Parse API response to release asset URI.
*
* @param string $git Name of API, eg 'github'.
* @param string $request Query to API->api().
* @param mixed $response API response.
* @return array|string|WP_Error $response Release asset download link.
*/
private function parse_release_asset( $git, $request, $response ) {
if ( is_wp_error( $response ) ) {
return '';
}
if ( in_array( $git, [ 'github', 'gitea' ], true ) ) {
if ( str_contains( $request, 'latest' ) ) {
// Convert single $response to array of releases.
$release = $response;
$response = [];
$response[] = $release ?? [];
}
$release_assets = [];
foreach ( $response as $release ) {
// Ignore leading 'v' and skip anything with dash or words.
if ( ! preg_match( '/[^v]+[-a-z]+/', $release->tag_name ) ) {
foreach ( $release->assets as $asset ) {
if ( str_starts_with( $asset->name, $this->type->slug ) ) {
$release_assets[ $release->tag_name ] = $asset->url;
continue 2;
}
}
}
}
uksort( $release_assets, fn ( $a, $b ) => version_compare( ltrim( $b, 'v' ), ltrim( $a, 'v' ) ) );
$response = $release_assets;
}
/**
* Filter release asset response.
*
* @since 10.0.0
* @param stdClass $response API response.
* @param string $git Name of git host.
* @param string $request Schema of API REST endpoint.
* @param stdClass $this Class object.
*/
$response = apply_filters( 'gu_parse_release_asset', $response, $git, $request, $this );
return $response;
}
/**
* Read the remote file and parse headers.
*
* @param string $git Name of API, eg 'github'.
* @param string $request API request.
*
* @return bool
*/
final public function get_remote_api_info( $git, $request ) {
$this->response = $this->get_repo_cache( $this->type->slug );
$response = $this->response[ $this->type->slug ] ?? false;
if ( ! $response ) {
self::$method = 'file';
$response = $this->api( $request );
$response = $this->decode_response( $git, $response );
}
if ( $response && is_string( $response ) ) {
$response = $this->get_file_headers( $response, $this->type->type );
$this->set_repo_cache( $this->type->slug, $response );
$this->set_repo_cache( 'repo', $this->type->slug );
}
if ( ! is_array( $response ) || $this->validate_response( $response ) ) {
return false;
}
$response['dot_org'] = $this->get_dot_org_data();
$this->set_file_info( $response );
return true;
}
/**
* Get remote info for tags.
*
* @param string $git Name of API, eg 'github'.
* @param string $request API request.
*
* @return bool
*/
final public function get_remote_api_tag( $git, $request ) {
$this->response = $this->get_repo_cache( $this->type->slug );
$repo_type = $this->return_repo_type();
$response = $this->response['tags'] ?? false;
if ( ! $response ) {
self::$method = 'tags';
$response = $this->api( $request );
if ( ! $response || is_wp_error( $response ) ) {
$response = new stdClass();
$response->message = 'No tags found';
}
if ( $response ) {
$response = $this->parse_tag_response( $response );
$this->set_repo_cache( 'tags', $response );
}
}
if ( $this->validate_response( $response ) ) {
return false;
}
$tags = $this->parse_tags( $response, $repo_type );
$this->sort_tags( $tags );
return true;
}
/**
* Read the remote CHANGES.md file.
*
* @param string $git Name of API, eg 'github'.
* @param string $changes Name of changelog file - deprecated.
* @param string $request API request.
*
* @return bool
*/
final public function get_remote_api_changes( $git, $changes, $request ) {
$changelogs = [ 'CHANGES.md', 'CHANGELOG.md', 'changes.md', 'changelog.md', 'changelog.txt' ];
$this->response = $this->get_repo_cache( $this->type->slug );
$response = $this->response['changes'] ?? false;
$changelogs = ! empty( $this->response['contents'] ) ? array_intersect( $this->response['contents']['files'], $changelogs ) : $changelogs;
if ( ! $response ) {
self::$method = 'changes';
foreach ( $changelogs as $changelog ) {
$new_request = str_replace( ':changelog', $changelog, $request );
$response = $this->api( $new_request );
$error = isset( $response->message );
$error = isset( $response->error ) ? true : $error;
if ( ! $error ) {
break;
}
}
$response = $this->decode_response( $git, $response );
if ( ! is_string( $response ) || is_wp_error( $response ) ) {
$response = new stdClass();
$response->message = 'No changelog found';
$this->set_repo_cache( 'changes', $response );
}
}
if ( $this->validate_response( $response ) && ! is_string( $response ) ) {
return false;
}
if ( ! isset( $this->response['changes'] ) ) {
$parser = new Parsedown();
$response = $parser->text( $response );
$this->set_repo_cache( 'changes', $response );
}
$this->type->sections['changelog'] = $response;
return true;
}
/**
* Read and parse remote readme.txt.
*
* @param string $git Name of API, eg 'github'.
* @param string $request API request.
*
* @return bool
*/
final public function get_remote_api_readme( $git, $request ) {
$readmes = [ 'readme.txt', 'README.md', 'readme.md' ];
$this->response = $this->get_repo_cache( $this->type->slug );
$response = $this->response['readme'] ?? false;
$readmes = ! empty( $this->response['contents'] ) ? array_intersect( $this->response['contents']['files'], $readmes ) : $readmes;
// Use readme.txt if it exists.
$readme_txt = array_filter(
$readmes,
function ( $readme ) {
if ( 'readme.txt' === $readme ) {
return $readme;
}
}
);
$readmes = array_unique( array_merge( $readme_txt, $readmes ) );
if ( ! $response ) {
self::$method = 'readme';
foreach ( $readmes as $readme ) {
$new_request = str_replace( ':readme', $readme, $request );
$response = $this->api( $new_request );
$error = isset( $response->message );
$error = isset( $response->error ) ? true : $error;
if ( ! $error ) {
break;
}
}
$response = $this->decode_response( $git, $response );
if ( ! is_string( $response ) || is_wp_error( $response ) ) {
$response = new stdClass();
$response->message = 'No readme found';
$this->set_repo_cache( 'readme', $response );
}
}
if ( $this->validate_response( $response ) ) {
return false;
}
if ( ! isset( $this->response['readme'] ) ) {
$parser = new Readme_Parser( $response );
$response = $parser->parse_data();
$this->set_repo_cache( 'readme', $response );
}
$this->set_readme_info( $response );
return true;
}
/**
* Read the repository meta from API.
*
* @param string $git Name of API, eg 'github'.
* @param string $request API request.
*
* @return bool
*/
final public function get_remote_api_repo_meta( $git, $request ) {
$this->response = $this->get_repo_cache( $this->type->slug );
$response = $this->response['meta'] ?? false;
if ( ! $response ) {
self::$method = 'meta';
$response = $this->api( $request );
if ( $response ) {
$response = $this->parse_meta_response( $response );
$this->set_repo_cache( 'meta', $response );
}
}
if ( $this->validate_response( $response ) ) {
return false;
}
$this->type->repo_meta = $response;
$this->add_meta_repo_object();
return true;
}
/**
* Read the assets folder of the repo.
*
* @param string $git Name of API, eg 'github'.
* @param string $request API request.
*
* @return bool
*/
final public function get_remote_api_assets( $git, $request ) {
$assets = [ '.wordpress-org', 'assets' ];
$this->response = $this->get_repo_cache( $this->type->slug );
$response = $this->response['assets'] ?? false;
$assets = ! empty( $this->response['contents'] ) ? array_intersect( (array) $this->response['contents']['dirs'], $assets ) : $assets;
if ( ! $response ) {
self::$method = 'assets';
foreach ( $assets as $asset ) {
$new_request = str_replace( ':path', $asset, $request );
$response = $this->api( $new_request );
if ( ! is_object( $response ) ) {
break;
}
}
$error = isset( $response->message );
$error = isset( $response->error ) ? true : $error;
$error = ! is_array( $response ) ? true : $error;
$error = is_wp_error( $response ) ? true : $error;
if ( $error ) {
$response = new stdClass();
$response->message = 'No assets found';
}
$response = $this->parse_asset_dir_response( $response );
$this->set_repo_cache( 'assets', $response );
}
if ( $this->validate_response( $response ) ) {
return false;
}
return true;
}
/**
* Create array of branches and download links as array.
*
* @param string $git Name of API, eg 'github'.
* @param string $request API request.
*
* @return bool
*/
final public function get_remote_api_branches( $git, $request ) {
$branches = [];
$this->response = $this->get_repo_cache( $this->type->slug );
$response = $this->response['branches'] ?? false;
if ( $this->exit_no_update( $response, true ) ) {
return false;
}
if ( ! $response ) {
self::$method = 'branches';
$response = $this->api( $request );
/**
* Filter API branch response.
*
* @since 10.0.0
* @param array|stdClass $response
* @param string $git Name of API, eg 'github'.
*/
$response = apply_filters( 'gu_parse_api_branches', $response, $git );
if ( $this->validate_response( $response ) || is_scalar( $response ) ) {
return false;
}
if ( $response ) {
$branches = $this->parse_branch_response( $response );
$this->type->branches = (array) $branches;
$this->set_repo_cache( 'branches', (array) $branches );
return true;
}
}
$this->type->branches = (array) $response;
return true;
}
/**
* Get API release asset download link.
*
* @param string $git Name of API, eg 'github'.
* @param string $request Query for API->api().
* @return string|array $response Release asset URI.
*/
final public function get_api_release_asset( $git, $request ) {
$this->response = $this->get_repo_cache( $this->type->slug );
$response = $this->response['release_asset'] ?? false;
if ( $response && $this->exit_no_update( $response ) ) {
return false;
}
if ( ! $response ) {
self::$method = 'release_asset';
$response = $this->api( $request );
$response = $this->parse_release_asset( $git, $request, $response );
if ( ! $response && ! is_wp_error( $response ) ) {
$response = new stdClass();
$response->message = 'No release asset found';
}
}
if ( $response && ! isset( $this->response['release_asset'] ) ) {
$this->type->release_assets[ $this->type->newest_tag ] = $response;
$this->set_repo_cache( 'release_asset', $response );
$this->set_repo_cache( 'release_asset_download', $response );
}
if ( $this->validate_response( $response ) ) {
return false;
}
$this->type->release_assets[ $this->type->newest_tag ] = $response;
return $response;
}
/**
* Get API release assets.
*
* @param string $git Name of API, eg 'github'.
* @param string $request Query for API->api().
* @return array $response Release asset URI.
*/
final public function get_api_release_assets( $git, $request ) {
$this->response = $this->get_repo_cache( $this->type->slug );
$response = $this->response['release_assets'] ?? false;
if ( $response && $this->exit_no_update( $response ) ) {
return false;
}
if ( ! $response ) {
self::$method = 'release_asset';
$response = $this->api( $request );
$response = $this->parse_release_asset( $git, $request, $response );
if ( ! $response && ! is_wp_error( $response ) ) {
$response = new stdClass();
$response->message = 'No release assets found';
}
}
if ( $response && ! isset( $this->response['release_assets'] ) ) {
$this->type->release_assets = $response;
$this->set_repo_cache( 'release_assets', $response );
}
if ( $this->validate_response( $response ) ) {
return false;
}
$this->type->release_assets = $response;
return $response;
}
/**
* Read the root contents of the repo.
*
* @param string $git Name of API, eg 'github'.
* @param string $request API request.
*
* @return bool
*/
final public function get_remote_api_contents( $git, $request ) {
$this->response = $this->get_repo_cache( $this->type->slug );
$response = $this->response['contents'] ?? false;
if ( ! $response ) {
self::$method = 'contents';
$response = $this->api( $request );
if ( $response ) {
$response = $this->parse_contents_response( $response );
$this->set_repo_cache( 'contents', $response );
}
}
if ( $this->validate_response( $response ) ) {
return false;
}
return true;
}
}