ajax.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. <?php
  2. class Meow_WR2X_Ajax {
  3. public $core = null;
  4. public function __construct( $core) {
  5. $this->core = $core;
  6. add_action( 'wp_ajax_wr2x_generate', array( $this, 'wp_ajax_wr2x_generate' ) );
  7. add_action( 'wp_ajax_wr2x_delete', array( $this, 'wp_ajax_wr2x_delete' ) );
  8. add_action( 'wp_ajax_wr2x_delete_full', array( $this, 'wp_ajax_wr2x_delete_full' ) );
  9. add_action( 'wp_ajax_wr2x_list_all', array( $this, 'wp_ajax_wr2x_list_all' ) );
  10. add_action( 'wp_ajax_wr2x_replace', array( $this, 'wp_ajax_wr2x_replace' ) );
  11. add_action( 'wp_ajax_wr2x_upload', array( $this, 'wp_ajax_wr2x_upload' ) );
  12. add_action( 'wp_ajax_wr2x_retina_upload', array( $this, 'wp_ajax_wr2x_retina_upload' ) );
  13. add_action( 'wp_ajax_wr2x_retina_details', array( $this, 'wp_ajax_wr2x_retina_details' ) );
  14. }
  15. /**
  16. * Checks nonce for the specified action
  17. * @param string $action
  18. */
  19. function check_nonce( $action ) {
  20. if ( !wp_verify_nonce( $_POST['nonce'], $action ) ) {
  21. echo json_encode(
  22. array (
  23. 'success' => false,
  24. 'message' => __( "Invalid API request.", 'wp-retina-2x' )
  25. )
  26. );
  27. die();
  28. }
  29. }
  30. /**
  31. * Checks if the current user has sufficient permissions to perform the Ajax actions
  32. */
  33. function check_capability() {
  34. $cap = 'upload_files';
  35. if ( !current_user_can( $cap ) ) {
  36. echo json_encode(
  37. array (
  38. 'success' => false,
  39. 'message' => __( "You do not have permission to upload files.", 'wp-retina-2x' )
  40. )
  41. );
  42. die();
  43. }
  44. }
  45. /**
  46. *
  47. * AJAX SERVER-SIDE
  48. *
  49. */
  50. // Using issuesOnly, only the IDs with a PENDING status will be processed
  51. function wp_ajax_wr2x_list_all( $issuesOnly ) {
  52. $this->check_nonce( 'wr2x_list_all' );
  53. $this->check_capability();
  54. $issuesOnly = intval( $_POST['issuesOnly'] );
  55. if ( $issuesOnly == 1 ) {
  56. $ids = $this->core->get_issues();
  57. echo json_encode(
  58. array(
  59. 'success' => true,
  60. 'message' => "List of issues only.",
  61. 'ids' => $ids,
  62. 'total' => count( $ids )
  63. ) );
  64. die;
  65. }
  66. $reply = array();
  67. try {
  68. $ids = array();
  69. $total = 0;
  70. global $wpdb;
  71. $postids = $wpdb->get_col( "
  72. SELECT p.ID
  73. FROM $wpdb->posts p
  74. WHERE post_status = 'inherit'
  75. AND post_type = 'attachment'
  76. AND ( post_mime_type = 'image/jpeg' OR
  77. post_mime_type = 'image/png' OR
  78. post_mime_type = 'image/gif' )
  79. " );
  80. foreach ($postids as $id) {
  81. if ( $this->core->is_ignore( $id ) )
  82. continue;
  83. array_push( $ids, $id );
  84. $total++;
  85. }
  86. echo json_encode(
  87. array(
  88. 'success' => true,
  89. 'message' => "List of everything.",
  90. 'ids' => $ids,
  91. 'total' => $total
  92. ) );
  93. die;
  94. }
  95. catch (Exception $e) {
  96. echo json_encode(
  97. array(
  98. 'success' => false,
  99. 'message' => $e->getMessage()
  100. ) );
  101. die;
  102. }
  103. }
  104. function wp_ajax_wr2x_delete_full( $pleaseReturn = false ) {
  105. if ( !$pleaseReturn ) $this->check_nonce( 'wr2x_delete_full' );
  106. $this->check_capability();
  107. if ( !isset( $_POST['attachmentId'] ) ) {
  108. echo json_encode(
  109. array(
  110. 'success' => false,
  111. 'message' => __( "The attachment ID is missing.", 'wp-retina-2x' )
  112. )
  113. );
  114. die();
  115. }
  116. $attachmentId = intval( $_POST['attachmentId'] );
  117. $originalfile = get_attached_file( $attachmentId );
  118. $pathinfo = pathinfo( $originalfile );
  119. $retina_file = trailingslashit( $pathinfo['dirname'] ) . $pathinfo['filename'] . $this->core->retina_extension() . $pathinfo['extension'];
  120. if ( $retina_file && file_exists( $retina_file ) )
  121. unlink( $retina_file );
  122. // RESULTS FOR RETINA DASHBOARD
  123. $info = $this->core->html_get_basic_retina_info_full( $attachmentId, $this->core->retina_info( $attachmentId ) );
  124. $results[$attachmentId] = $info;
  125. // Return if that's not the final step.
  126. if ( $pleaseReturn )
  127. return $info;
  128. echo json_encode(
  129. array(
  130. 'results' => $results,
  131. 'success' => true,
  132. 'message' => __( "Full retina file deleted.", 'wp-retina-2x' )
  133. )
  134. );
  135. die();
  136. }
  137. function wp_ajax_wr2x_delete() {
  138. $this->check_nonce( 'wr2x_delete' );
  139. $this->check_capability();
  140. if ( !isset( $_POST['attachmentId'] ) ) {
  141. echo json_encode(
  142. array(
  143. 'success' => false,
  144. 'message' => __( "The attachment ID is missing.", 'wp-retina-2x' )
  145. )
  146. );
  147. die();
  148. }
  149. // Information for the retina version of the full-size
  150. $attachmentId = intval( $_POST['attachmentId'] );
  151. $results_full[$attachmentId] = $this->wp_ajax_wr2x_delete_full( true );
  152. $this->core->delete_attachment( $attachmentId, true );
  153. $meta = wp_get_attachment_metadata( $attachmentId );
  154. // RESULTS FOR RETINA DASHBOARD
  155. $this->core->update_issue_status( $attachmentId );
  156. $info = $this->core->html_get_basic_retina_info( $attachmentId, $this->core->retina_info( $attachmentId ) );
  157. $results[$attachmentId] = $info;
  158. echo json_encode(
  159. array(
  160. 'results' => $results,
  161. 'results_full' => $results_full,
  162. 'success' => true,
  163. 'message' => __( "Retina files deleted.", 'wp-retina-2x' )
  164. )
  165. );
  166. die();
  167. }
  168. function wp_ajax_wr2x_retina_details() {
  169. $this->check_nonce( 'wr2x_retina_details' );
  170. $this->check_capability();
  171. if ( !isset( $_POST['attachmentId'] ) ) {
  172. echo json_encode(
  173. array(
  174. 'success' => false,
  175. 'message' => __( "The attachment ID is missing.", 'wp-retina-2x' )
  176. )
  177. );
  178. die();
  179. }
  180. $attachmentId = intval( $_POST['attachmentId'] );
  181. $info = $this->core->html_get_details_retina_info( $attachmentId, $this->core->retina_info( $attachmentId ) );
  182. echo json_encode(
  183. array(
  184. 'result' => $info,
  185. 'success' => true,
  186. 'message' => __( "Details retrieved.", 'wp-retina-2x' )
  187. )
  188. );
  189. die();
  190. }
  191. function wp_ajax_wr2x_generate() {
  192. $this->check_nonce( 'wr2x_generate' );
  193. $this->check_capability();
  194. if ( !isset( $_POST['attachmentId'] ) ) {
  195. echo json_encode(
  196. array(
  197. 'success' => false,
  198. 'message' => __( "The attachment ID is missing.", 'wp-retina-2x' )
  199. )
  200. );
  201. die();
  202. }
  203. $attachmentId = intval( $_POST['attachmentId'] );
  204. $this->core->delete_attachment( $attachmentId, false );
  205. // Regenerate the Thumbnails
  206. $regenerate = get_option( 'wr2x_regenerate_thumbnails', false );
  207. if ( $regenerate ) {
  208. $file = get_attached_file( $attachmentId );
  209. $meta = wp_generate_attachment_metadata( $attachmentId, $file );
  210. wp_update_attachment_metadata( $attachmentId, $meta );
  211. }
  212. // Regenerate Retina
  213. $meta = wp_get_attachment_metadata( $attachmentId );
  214. $this->core->generate_images( $meta );
  215. // RESULTS FOR RETINA DASHBOARD
  216. $info = $this->core->html_get_basic_retina_info( $attachmentId, $this->core->retina_info( $attachmentId ) );
  217. $results[$attachmentId] = $info;
  218. echo json_encode(
  219. array(
  220. 'results' => $results,
  221. 'success' => true,
  222. 'message' => __( "Retina files generated.", 'wp-retina-2x' )
  223. )
  224. );
  225. die();
  226. }
  227. function check_get_ajax_uploaded_file() {
  228. $this->check_capability();
  229. $tmpfname = $_FILES['file']['tmp_name'];
  230. // Check if it is an image
  231. $file_info = getimagesize( $tmpfname );
  232. if ( empty( $file_info ) ) {
  233. $this->core->log( "The file is not an image or the upload went wrong." );
  234. unlink( $tmpfname );
  235. echo json_encode( array(
  236. 'success' => false,
  237. 'message' => __( "The file is not an image or the upload went wrong.", 'wp-retina-2x' )
  238. ));
  239. die();
  240. }
  241. $filedata = wp_check_filetype_and_ext( $tmpfname, $_POST['filename'] );
  242. if ( $filedata["ext"] == "" ) {
  243. $this->core->log( "You cannot use this file (wrong extension? wrong type?)." );
  244. unlink( $current_file );
  245. echo json_encode( array(
  246. 'success' => false,
  247. 'message' => __( "You cannot use this file (wrong extension? wrong type?).", 'wp-retina-2x' )
  248. ));
  249. die();
  250. }
  251. $this->core->log( "The temporary file was written successfully." );
  252. return $tmpfname;
  253. }
  254. function wp_ajax_wr2x_upload( $checksNonce = true ) {
  255. if ( $checksNonce ) $this->check_nonce( 'wr2x_upload' );
  256. try {
  257. $tmpfname = $this->check_get_ajax_uploaded_file();
  258. $attachmentId = (int) $_POST['attachmentId'];
  259. $meta = wp_get_attachment_metadata( $attachmentId );
  260. $current_file = get_attached_file( $attachmentId );
  261. $pathinfo = pathinfo( $current_file );
  262. $basepath = $pathinfo['dirname'];
  263. $retinafile = trailingslashit( $pathinfo['dirname'] ) . $pathinfo['filename'] . $this->core->retina_extension() . $pathinfo['extension'];
  264. if ( file_exists( $retinafile ) )
  265. unlink( $retinafile );
  266. // Insert the new file and delete the temporary one
  267. list( $width, $height ) = getimagesize( $tmpfname );
  268. if ( !$this->core->are_dimensions_ok( $width, $height, $meta['width'] * 2, $meta['height'] * 2 ) ) {
  269. echo json_encode( array(
  270. 'success' => false,
  271. 'message' => "This image has a resolution of ${width}×${height} but your Full Size image requires a retina image of at least " . ( $meta['width'] * 2 ) . "x" . ( $meta['height'] * 2 ) . "."
  272. ));
  273. die();
  274. }
  275. $this->core->resize( $tmpfname, $meta['width'] * 2, $meta['height'] * 2, null, $retinafile );
  276. chmod( $retinafile, 0644 );
  277. unlink( $tmpfname );
  278. // Get the results
  279. $info = $this->core->retina_info( $attachmentId );
  280. $this->core->update_issue_status( $attachmentId );
  281. $results[$attachmentId] = $this->core->html_get_basic_retina_info_full( $attachmentId, $info );
  282. }
  283. catch (Exception $e) {
  284. echo json_encode( array(
  285. 'success' => false,
  286. 'results' => null,
  287. 'message' => __( "Error: " . $e->getMessage(), 'wp-retina-2x' )
  288. ));
  289. die();
  290. }
  291. echo json_encode( array(
  292. 'success' => true,
  293. 'results' => $results,
  294. 'message' => __( "Uploaded successfully.", 'wp-retina-2x' ),
  295. 'media' => array(
  296. 'id' => $attachmentId,
  297. 'src' => wp_get_attachment_image_src( $attachmentId, 'thumbnail' ),
  298. 'edit_url' => get_edit_post_link( $attachmentId, 'attribute' )
  299. )
  300. ));
  301. die();
  302. }
  303. function wp_ajax_wr2x_retina_upload() {
  304. require_once ABSPATH . 'wp-admin/includes/image.php';
  305. $this->check_nonce( 'wr2x_retina_upload' );
  306. $this->check_capability();
  307. try {
  308. $tmpf = $this->check_get_ajax_uploaded_file();
  309. $image = wp_get_image_editor( $tmpf );
  310. $size = $image->get_size();
  311. // Halve the size of the uploaded image
  312. if ( $size['width'] >= $size['height'] ) $image->resize( round($size['width'] * .5), null );
  313. else $image->resize( null, round($size['height'] * .5) );
  314. $image->set_quality( get_option('wr2x_quality', 90) );
  315. $halved = $image->save( $tmpf . 'H' );
  316. if ( !$halved ) throw new Exception( "Failed to halve the uploaded image" );
  317. if ( is_wp_error($halved) ) throw new Exception( $halved->get_error_message() );
  318. // Upload the halved image
  319. $content = file_get_contents( $halved['path'] );
  320. if ( $content === false ) throw new Exception( "Couldn't read the uploaded file: {$halved['file']}" );
  321. $uploaded = wp_upload_bits( $_POST['filename'], null, $content );
  322. if ( isset($uploaded['error']) && $uploaded['error'] ) throw new Exception( $uploaded['error'] );
  323. // Register the file as a new attachment
  324. $attachTo = 0; // TODO Support specifying which post the media attach to
  325. $ftype = wp_check_filetype( $uploaded['file'] );
  326. $attachment = array (
  327. 'post_mime_type' => $ftype['type'],
  328. 'post_parent' => $attachTo,
  329. 'post_title' => preg_replace( '/\.[^.]+$/', '', $_POST['filename'] ),
  330. 'post_content' => '',
  331. 'post_status' => 'inherit'
  332. );
  333. $attachmentId = wp_insert_attachment( $attachment, $uploaded['file'], $attachTo );
  334. if ( !$attachmentId ) throw new Exception( "Couldn't add an attachment file: {$uploaded['file']}" );
  335. if ( is_wp_error($attachmentId) ) throw new Exception( $attachmentId->get_error_message() );
  336. $meta = wp_generate_attachment_metadata( $attachmentId, $uploaded['file'] );
  337. wp_update_attachment_metadata( $attachmentId, $meta );
  338. } catch ( Exception $e ) {
  339. echo json_encode( array (
  340. 'success' => false,
  341. 'results' => null,
  342. 'message' => __( "Error: " . $e->getMessage(), 'wp-retina-2x' )
  343. ));
  344. die();
  345. }
  346. // Redirect to 'wr2x_upload'
  347. $_POST['attachmentId'] = $attachmentId;
  348. $this->wp_ajax_wr2x_upload( false );
  349. }
  350. function wp_ajax_wr2x_replace() {
  351. $this->check_nonce( 'wr2x_replace' );
  352. $tmpfname = $this->check_get_ajax_uploaded_file();
  353. $attachmentId = (int) $_POST['attachmentId'];
  354. $meta = wp_get_attachment_metadata( $attachmentId );
  355. $current_file = get_attached_file( $attachmentId );
  356. $this->core->delete_attachment( $attachmentId, false );
  357. $pathinfo = pathinfo( $current_file );
  358. $basepath = $pathinfo['dirname'];
  359. // Let's clean everything first
  360. if ( wp_attachment_is_image( $attachmentId ) ) {
  361. $sizes = $this->core->get_image_sizes();
  362. foreach ($sizes as $name => $attr) {
  363. if ( isset( $meta['sizes'][$name] ) && isset( $meta['sizes'][$name]['file'] ) && file_exists( trailingslashit( $basepath ) . $meta['sizes'][$name]['file'] ) ) {
  364. $normal_file = trailingslashit( $basepath ) . $meta['sizes'][$name]['file'];
  365. $pathinfo = pathinfo( $normal_file );
  366. $retina_file = trailingslashit( $pathinfo['dirname'] ) . $pathinfo['filename'] . $this->core->retina_extension() . $pathinfo['extension'];
  367. // Test if the file exists and if it is actually a file (and not a dir)
  368. // Some old WordPress Media Library are sometimes broken and link to directories
  369. if ( file_exists( $normal_file ) && is_file( $normal_file ) )
  370. unlink( $normal_file );
  371. if ( file_exists( $retina_file ) && is_file( $retina_file ) )
  372. unlink( $retina_file );
  373. }
  374. }
  375. }
  376. if ( file_exists( $current_file ) )
  377. unlink( $current_file );
  378. // Insert the new file and delete the temporary one
  379. rename( $tmpfname, $current_file );
  380. chmod( $current_file, 0644 );
  381. // Generate the images
  382. wp_update_attachment_metadata( $attachmentId, wp_generate_attachment_metadata( $attachmentId, $current_file ) );
  383. $meta = wp_get_attachment_metadata( $attachmentId );
  384. $this->core->generate_images( $meta );
  385. // Get the results
  386. $info = $this->core->retina_info( $attachmentId );
  387. $results[$attachmentId] = $this->core->html_get_basic_retina_info( $attachmentId, $info );
  388. echo json_encode( array(
  389. 'success' => true,
  390. 'results' => $results,
  391. 'message' => __( "Replaced successfully.", 'wp-retina-2x' )
  392. ));
  393. die();
  394. }
  395. }
  396. ?>