PageRenderTime 66ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-endpoint.php

https://gitlab.com/chernushov881/charity-fund
PHP | 362 lines | 284 code | 59 blank | 19 comment | 55 complexity | 4c42a89b67d49fde26f321029c2a776b MD5 | raw file
  1. <?php
  2. use Automattic\Jetpack\Constants;
  3. use Automattic\Jetpack\Sync\Functions;
  4. /**
  5. * Base class for working with plugins.
  6. */
  7. abstract class Jetpack_JSON_API_Plugins_Endpoint extends Jetpack_JSON_API_Endpoint {
  8. protected $plugins = array();
  9. protected $network_wide = false;
  10. protected $bulk = true;
  11. protected $log;
  12. static $_response_format = array(
  13. 'id' => '(safehtml) The plugin\'s ID',
  14. 'slug' => '(safehtml) The plugin\'s .org slug',
  15. 'active' => '(boolean) The plugin status.',
  16. 'update' => '(object) The plugin update info.',
  17. 'name' => '(safehtml) The name of the plugin.',
  18. 'plugin_url' => '(url) Link to the plugin\'s web site.',
  19. 'version' => '(safehtml) The plugin version number.',
  20. 'description' => '(safehtml) Description of what the plugin does and/or notes from the author',
  21. 'author' => '(safehtml) The author\'s name',
  22. 'author_url' => '(url) The authors web site address',
  23. 'network' => '(boolean) Whether the plugin can only be activated network wide.',
  24. 'autoupdate' => '(boolean) Whether the plugin is automatically updated',
  25. 'autoupdate_translation' => '(boolean) Whether the plugin is automatically updating translations',
  26. 'next_autoupdate' => '(string) Y-m-d H:i:s for next scheduled update event',
  27. 'log' => '(array:safehtml) An array of update log strings.',
  28. 'uninstallable' => '(boolean) Whether the plugin is unistallable.',
  29. 'action_links' => '(array) An array of action links that the plugin uses.',
  30. );
  31. static $_response_format_v1_2 = array(
  32. 'slug' => '(safehtml) The plugin\'s .org slug',
  33. 'active' => '(boolean) The plugin status.',
  34. 'update' => '(object) The plugin update info.',
  35. 'name' => '(safehtml) The plugin\'s ID',
  36. 'display_name' => '(safehtml) The name of the plugin.',
  37. 'version' => '(safehtml) The plugin version number.',
  38. 'description' => '(safehtml) Description of what the plugin does and/or notes from the author',
  39. 'author' => '(safehtml) The author\'s name',
  40. 'author_url' => '(url) The authors web site address',
  41. 'plugin_url' => '(url) Link to the plugin\'s web site.',
  42. 'network' => '(boolean) Whether the plugin can only be activated network wide.',
  43. 'autoupdate' => '(boolean) Whether the plugin is automatically updated',
  44. 'autoupdate_translation' => '(boolean) Whether the plugin is automatically updating translations',
  45. 'uninstallable' => '(boolean) Whether the plugin is unistallable.',
  46. 'action_links' => '(array) An array of action links that the plugin uses.',
  47. 'log' => '(array:safehtml) An array of update log strings.',
  48. );
  49. protected function result() {
  50. $plugins = $this->get_plugins();
  51. if ( ! $this->bulk && ! empty( $plugins ) ) {
  52. return array_pop( $plugins );
  53. }
  54. return array( 'plugins' => $plugins );
  55. }
  56. protected function validate_input( $plugin ) {
  57. if ( is_wp_error( $error = parent::validate_input( $plugin ) ) ) {
  58. return $error;
  59. }
  60. if ( is_wp_error( $error = $this->validate_network_wide() ) ) {
  61. return $error;
  62. }
  63. $args = $this->input();
  64. // find out what plugin, or plugins we are dealing with
  65. // validate the requested plugins
  66. if ( ! isset( $plugin ) || empty( $plugin ) ) {
  67. if ( ! $args['plugins'] || empty( $args['plugins'] ) ) {
  68. return new WP_Error( 'missing_plugin', __( 'You are required to specify a plugin.', 'jetpack' ), 400 );
  69. }
  70. if ( is_array( $args['plugins'] ) ) {
  71. $this->plugins = $args['plugins'];
  72. } else {
  73. $this->plugins[] = $args['plugins'];
  74. }
  75. } else {
  76. $this->bulk = false;
  77. $this->plugins[] = urldecode( $plugin );
  78. }
  79. if ( is_wp_error( $error = $this->validate_plugins() ) ) {
  80. return $error;
  81. };
  82. return true;
  83. }
  84. /**
  85. * Walks through submitted plugins to make sure they are valid
  86. * @return bool|WP_Error
  87. */
  88. protected function validate_plugins() {
  89. if ( empty( $this->plugins ) || ! is_array( $this->plugins ) ) {
  90. return new WP_Error( 'missing_plugins', __( 'No plugins found.', 'jetpack' ));
  91. }
  92. foreach( $this->plugins as $index => $plugin ) {
  93. if ( ! preg_match( "/\.php$/", $plugin ) ) {
  94. $plugin = $plugin . '.php';
  95. $this->plugins[ $index ] = $plugin;
  96. }
  97. $valid = $this->validate_plugin( urldecode( $plugin ) ) ;
  98. if ( is_wp_error( $valid ) ) {
  99. return $valid;
  100. }
  101. }
  102. return true;
  103. }
  104. protected function format_plugin( $plugin_file, $plugin_data ) {
  105. if ( version_compare( $this->min_version, '1.2', '>=' ) ) {
  106. return $this->format_plugin_v1_2( $plugin_file, $plugin_data );
  107. }
  108. $plugin = array();
  109. $plugin['id'] = preg_replace("/(.+)\.php$/", "$1", $plugin_file );
  110. $plugin['slug'] = Jetpack_Autoupdate::get_plugin_slug( $plugin_file );
  111. $plugin['active'] = Jetpack::is_plugin_active( $plugin_file );
  112. $plugin['name'] = $plugin_data['Name'];
  113. $plugin['plugin_url'] = $plugin_data['PluginURI'];
  114. $plugin['version'] = $plugin_data['Version'];
  115. $plugin['description'] = $plugin_data['Description'];
  116. $plugin['author'] = $plugin_data['Author'];
  117. $plugin['author_url'] = $plugin_data['AuthorURI'];
  118. $plugin['network'] = $plugin_data['Network'];
  119. $plugin['update'] = $this->get_plugin_updates( $plugin_file );
  120. $plugin['next_autoupdate'] = date( 'Y-m-d H:i:s', wp_next_scheduled( 'wp_maybe_auto_update' ) );
  121. $action_link = $this->get_plugin_action_links( $plugin_file );
  122. if ( ! empty( $action_link ) ) {
  123. $plugin['action_links'] = $action_link;
  124. }
  125. $plugin['plugin'] = $plugin_file;
  126. if ( ! class_exists( 'WP_Automatic_Updater' ) ) {
  127. require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
  128. }
  129. $autoupdate = ( new WP_Automatic_Updater() )->should_update( 'plugin', (object) $plugin, WP_PLUGIN_DIR );
  130. $plugin['autoupdate'] = $autoupdate;
  131. $autoupdate_translation = in_array( $plugin_file, Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() ) );
  132. $plugin['autoupdate_translation'] = $autoupdate || $autoupdate_translation || Jetpack_Options::get_option( 'autoupdate_translations', false );
  133. $plugin['uninstallable'] = is_uninstallable_plugin( $plugin_file );
  134. if ( is_multisite() ) {
  135. $plugin['network_active'] = is_plugin_active_for_network( $plugin_file );
  136. }
  137. if ( ! empty ( $this->log[ $plugin_file ] ) ) {
  138. $plugin['log'] = $this->log[ $plugin_file ];
  139. }
  140. return $plugin;
  141. }
  142. protected function format_plugin_v1_2( $plugin_file, $plugin_data ) {
  143. $plugin = array();
  144. $plugin['slug'] = Jetpack_Autoupdate::get_plugin_slug( $plugin_file );
  145. $plugin['active'] = Jetpack::is_plugin_active( $plugin_file );
  146. $plugin['name'] = preg_replace("/(.+)\.php$/", "$1", $plugin_file );
  147. $plugin['display_name'] = $plugin_data['Name'];
  148. $plugin['plugin_url'] = $plugin_data['PluginURI'];
  149. $plugin['version'] = $plugin_data['Version'];
  150. $plugin['description'] = $plugin_data['Description'];
  151. $plugin['author'] = $plugin_data['Author'];
  152. $plugin['author_url'] = $plugin_data['AuthorURI'];
  153. $plugin['network'] = $plugin_data['Network'];
  154. $plugin['update'] = $this->get_plugin_updates( $plugin_file );
  155. $action_link = $this->get_plugin_action_links( $plugin_file );
  156. if ( ! empty( $action_link ) ) {
  157. $plugin['action_links'] = $action_link;
  158. }
  159. $plugin['plugin'] = $plugin_file;
  160. if ( ! class_exists( 'WP_Automatic_Updater' ) ) {
  161. require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
  162. }
  163. $autoupdate = ( new WP_Automatic_Updater() )->should_update( 'plugin', (object) $plugin, WP_PLUGIN_DIR );
  164. $plugin['autoupdate'] = $autoupdate;
  165. $autoupdate_translation = $this->plugin_has_translations_autoupdates_enabled( $plugin_file );
  166. $plugin['autoupdate_translation'] = $autoupdate || $autoupdate_translation || Jetpack_Options::get_option( 'autoupdate_translations', false );
  167. $plugin['uninstallable'] = is_uninstallable_plugin( $plugin_file );
  168. if ( is_multisite() ) {
  169. $plugin['network_active'] = is_plugin_active_for_network( $plugin_file );
  170. }
  171. if ( ! empty ( $this->log[ $plugin_file ] ) ) {
  172. $plugin['log'] = $this->log[ $plugin_file ];
  173. }
  174. return $plugin;
  175. }
  176. protected function plugin_has_translations_autoupdates_enabled( $plugin_file ) {
  177. return (bool) in_array( $plugin_file, Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() ) );
  178. }
  179. protected function get_file_mod_capabilities() {
  180. $reasons_can_not_autoupdate = array();
  181. $reasons_can_not_modify_files = array();
  182. $has_file_system_write_access = Functions::file_system_write_access();
  183. if ( ! $has_file_system_write_access ) {
  184. $reasons_can_not_modify_files['has_no_file_system_write_access'] = __( 'The file permissions on this host prevent editing files.', 'jetpack' );
  185. }
  186. $disallow_file_mods = Constants::get_constant('DISALLOW_FILE_MODS' );
  187. if ( $disallow_file_mods ) {
  188. $reasons_can_not_modify_files['disallow_file_mods'] = __( 'File modifications are explicitly disabled by a site administrator.', 'jetpack' );
  189. }
  190. $automatic_updater_disabled = Constants::get_constant( 'AUTOMATIC_UPDATER_DISABLED' );
  191. if ( $automatic_updater_disabled ) {
  192. $reasons_can_not_autoupdate['automatic_updater_disabled'] = __( 'Any autoupdates are explicitly disabled by a site administrator.', 'jetpack' );
  193. }
  194. if ( is_multisite() ) {
  195. // is it the main network ? is really is multi network
  196. if ( Jetpack::is_multi_network() ) {
  197. $reasons_can_not_modify_files['is_multi_network'] = __( 'Multi network install are not supported.', 'jetpack' );
  198. }
  199. // Is the site the main site here.
  200. if ( ! is_main_site() ) {
  201. $reasons_can_not_modify_files['is_sub_site'] = __( 'The site is not the main network site', 'jetpack' );
  202. }
  203. }
  204. $file_mod_capabilities = array(
  205. 'modify_files' => (bool) empty( $reasons_can_not_modify_files ), // install, remove, update
  206. 'autoupdate_files' => (bool) empty( $reasons_can_not_modify_files ) && empty( $reasons_can_not_autoupdate ), // enable autoupdates
  207. );
  208. if ( ! empty( $reasons_can_not_modify_files ) ) {
  209. $file_mod_capabilities['reasons_modify_files_unavailable'] = $reasons_can_not_modify_files;
  210. }
  211. if ( ! $file_mod_capabilities['autoupdate_files'] ) {
  212. $file_mod_capabilities['reasons_autoupdate_unavailable'] = array_merge( $reasons_can_not_autoupdate, $reasons_can_not_modify_files );
  213. }
  214. return $file_mod_capabilities;
  215. }
  216. protected function get_plugins() {
  217. $plugins = array();
  218. /** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */
  219. $installed_plugins = apply_filters( 'all_plugins', get_plugins() );
  220. foreach ( $this->plugins as $plugin ) {
  221. if ( ! isset( $installed_plugins[ $plugin ] ) ) {
  222. continue;
  223. }
  224. $formatted_plugin = $this->format_plugin( $plugin, $installed_plugins[ $plugin ] );
  225. // If this endpoint accepts site based authentication and a blog token is used, skip capabilities check.
  226. if ( $this->accepts_site_based_authentication() ) {
  227. $plugins[] = $formatted_plugin;
  228. continue;
  229. }
  230. /*
  231. * Do not show network-active plugins
  232. * to folks who do not have the permission to see them.
  233. */
  234. if (
  235. /** This filter is documented in src/wp-admin/includes/class-wp-plugins-list-table.php */
  236. ! apply_filters( 'show_network_active_plugins', current_user_can( 'manage_network_plugins' ) )
  237. && ! empty( $formatted_plugin['network_active'] )
  238. && true === $formatted_plugin['network_active']
  239. ) {
  240. continue;
  241. }
  242. $plugins[] = $formatted_plugin;
  243. }
  244. $args = $this->query_args();
  245. if ( isset( $args['offset'] ) ) {
  246. $plugins = array_slice( $plugins, (int) $args['offset'] );
  247. }
  248. if ( isset( $args['limit'] ) ) {
  249. $plugins = array_slice( $plugins, 0, (int) $args['limit'] );
  250. }
  251. return $plugins;
  252. }
  253. protected function validate_network_wide() {
  254. $args = $this->input();
  255. if ( isset( $args['network_wide'] ) && $args['network_wide'] ) {
  256. $this->network_wide = true;
  257. }
  258. // If this endpoint accepts site based authentication and a blog token is used, skip capabilities check.
  259. if ( $this->accepts_site_based_authentication() ) {
  260. return true;
  261. }
  262. if ( $this->network_wide && ! current_user_can( 'manage_network_plugins' ) ) {
  263. return new WP_Error( 'unauthorized', __( 'This user is not authorized to manage plugins network wide.', 'jetpack' ), 403 );
  264. }
  265. return true;
  266. }
  267. protected function validate_plugin( $plugin ) {
  268. if ( ! isset( $plugin) || empty( $plugin ) ) {
  269. return new WP_Error( 'missing_plugin', __( 'You are required to specify a plugin to activate.', 'jetpack' ), 400 );
  270. }
  271. if ( is_wp_error( $error = validate_plugin( $plugin ) ) ) {
  272. return new WP_Error( 'unknown_plugin', $error->get_error_messages() , 404 );
  273. }
  274. return true;
  275. }
  276. protected function get_plugin_updates( $plugin_file ) {
  277. $plugin_updates = get_plugin_updates();
  278. if ( isset( $plugin_updates[ $plugin_file ] ) ) {
  279. $update = $plugin_updates[ $plugin_file ]->update;
  280. $cleaned_update = array();
  281. foreach( (array) $update as $update_key => $update_value ) {
  282. switch ( $update_key ) {
  283. case 'id':
  284. case 'slug':
  285. case 'plugin':
  286. case 'new_version':
  287. case 'tested':
  288. $cleaned_update[ $update_key ] = wp_kses( $update_value, array() );
  289. break;
  290. case 'url':
  291. case 'package':
  292. $cleaned_update[ $update_key ] = esc_url( $update_value );
  293. break;
  294. }
  295. }
  296. return (object) $cleaned_update;
  297. }
  298. return null;
  299. }
  300. protected function get_plugin_action_links( $plugin_file ) {
  301. return Functions::get_plugins_action_links( $plugin_file );
  302. }
  303. }