integration.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. <?php
  2. class WPCF7_Integration {
  3. private static $instance;
  4. private $services = array();
  5. private $categories = array();
  6. private function __construct() {}
  7. public static function get_instance() {
  8. if ( empty( self::$instance ) ) {
  9. self::$instance = new self;
  10. }
  11. return self::$instance;
  12. }
  13. public function add_service( $name, WPCF7_Service $service ) {
  14. $name = sanitize_key( $name );
  15. if ( empty( $name )
  16. or isset( $this->services[$name] ) ) {
  17. return false;
  18. }
  19. $this->services[$name] = $service;
  20. }
  21. public function add_category( $name, $title ) {
  22. $name = sanitize_key( $name );
  23. if ( empty( $name )
  24. or isset( $this->categories[$name] ) ) {
  25. return false;
  26. }
  27. $this->categories[$name] = $title;
  28. }
  29. public function service_exists( $name = '' ) {
  30. if ( '' == $name ) {
  31. return (bool) count( $this->services );
  32. } else {
  33. return isset( $this->services[$name] );
  34. }
  35. }
  36. public function get_service( $name ) {
  37. if ( $this->service_exists( $name ) ) {
  38. return $this->services[$name];
  39. } else {
  40. return false;
  41. }
  42. }
  43. public function list_services( $args = '' ) {
  44. $args = wp_parse_args( $args, array(
  45. 'include' => array(),
  46. ) );
  47. $singular = false;
  48. $services = (array) $this->services;
  49. if ( ! empty( $args['include'] ) ) {
  50. $services = array_intersect_key( $services,
  51. array_flip( (array) $args['include'] ) );
  52. if ( 1 == count( $services ) ) {
  53. $singular = true;
  54. }
  55. }
  56. if ( empty( $services ) ) {
  57. return;
  58. }
  59. $action = wpcf7_current_action();
  60. foreach ( $services as $name => $service ) {
  61. $cats = array_intersect_key( $this->categories,
  62. array_flip( $service->get_categories() ) );
  63. ?>
  64. <div class="card<?php echo $service->is_active() ? ' active' : ''; ?>" id="<?php echo esc_attr( $name ); ?>">
  65. <?php $service->icon(); ?>
  66. <h2 class="title"><?php echo esc_html( $service->get_title() ); ?></h2>
  67. <div class="infobox">
  68. <?php echo esc_html( implode( ', ', $cats ) ); ?>
  69. <br />
  70. <?php $service->link(); ?>
  71. </div>
  72. <br class="clear" />
  73. <div class="inside">
  74. <?php
  75. if ( $singular ) {
  76. $service->display( $action );
  77. } else {
  78. $service->display();
  79. }
  80. ?>
  81. </div>
  82. </div>
  83. <?php
  84. }
  85. }
  86. }
  87. abstract class WPCF7_Service {
  88. abstract public function get_title();
  89. abstract public function is_active();
  90. public function get_categories() {
  91. return array();
  92. }
  93. public function icon() {
  94. return '';
  95. }
  96. public function link() {
  97. return '';
  98. }
  99. public function load( $action = '' ) {
  100. }
  101. public function display( $action = '' ) {
  102. }
  103. public function admin_notice( $message = '' ) {
  104. }
  105. }
  106. class WPCF7_Service_OAuth2 extends WPCF7_Service {
  107. protected $client_id = '';
  108. protected $client_secret = '';
  109. protected $access_token = '';
  110. protected $refresh_token = '';
  111. protected $authorization_endpoint = 'https://example.com/authorization';
  112. protected $token_endpoint = 'https://example.com/token';
  113. public function get_title() {
  114. return '';
  115. }
  116. public function is_active() {
  117. return ! empty( $this->refresh_token );
  118. }
  119. protected function save_data() {
  120. }
  121. protected function reset_data() {
  122. }
  123. protected function get_redirect_uri() {
  124. return admin_url();
  125. }
  126. protected function menu_page_url( $args = '' ) {
  127. return menu_page_url( 'wpcf7-integration', false );
  128. }
  129. public function load( $action = '' ) {
  130. if ( 'auth_redirect' == $action ) {
  131. $code = isset( $_GET['code'] ) ? $_GET['code'] : '';
  132. if ( $code ) {
  133. $this->request_token( $code );
  134. }
  135. if ( ! empty( $this->access_token ) ) {
  136. $message = 'success';
  137. } else {
  138. $message = 'failed';
  139. }
  140. wp_safe_redirect( $this->menu_page_url(
  141. array(
  142. 'action' => 'setup',
  143. 'message' => $message,
  144. )
  145. ) );
  146. exit();
  147. }
  148. }
  149. protected function authorize( $scope = '' ) {
  150. $endpoint = add_query_arg(
  151. array(
  152. 'response_type' => 'code',
  153. 'client_id' => $this->client_id,
  154. 'redirect_uri' => urlencode( $this->get_redirect_uri() ),
  155. 'scope' => $scope,
  156. ),
  157. $this->authorization_endpoint
  158. );
  159. if ( wp_redirect( esc_url_raw( $endpoint ) ) ) {
  160. exit();
  161. }
  162. }
  163. protected function get_http_authorization_header( $scheme = 'basic' ) {
  164. $scheme = strtolower( trim( $scheme ) );
  165. switch ( $scheme ) {
  166. case 'bearer':
  167. return sprintf( 'Bearer %s', $this->access_token );
  168. case 'basic':
  169. default:
  170. return sprintf( 'Basic %s',
  171. base64_encode( $this->client_id . ':' . $this->client_secret )
  172. );
  173. }
  174. }
  175. protected function request_token( $authorization_code ) {
  176. $endpoint = add_query_arg(
  177. array(
  178. 'code' => $authorization_code,
  179. 'redirect_uri' => urlencode( $this->get_redirect_uri() ),
  180. 'grant_type' => 'authorization_code',
  181. ),
  182. $this->token_endpoint
  183. );
  184. $request = array(
  185. 'headers' => array(
  186. 'Authorization' => $this->get_http_authorization_header( 'basic' ),
  187. ),
  188. );
  189. $response = wp_remote_post( esc_url_raw( $endpoint ), $request );
  190. $response_code = (int) wp_remote_retrieve_response_code( $response );
  191. $response_body = wp_remote_retrieve_body( $response );
  192. $response_body = json_decode( $response_body, true );
  193. if ( WP_DEBUG and 400 <= $response_code ) {
  194. $this->log( $endpoint, $request, $response );
  195. }
  196. if ( 401 == $response_code ) { // Unauthorized
  197. $this->access_token = null;
  198. $this->refresh_token = null;
  199. } else {
  200. if ( isset( $response_body['access_token'] ) ) {
  201. $this->access_token = $response_body['access_token'];
  202. } else {
  203. $this->access_token = null;
  204. }
  205. if ( isset( $response_body['refresh_token'] ) ) {
  206. $this->refresh_token = $response_body['refresh_token'];
  207. } else {
  208. $this->refresh_token = null;
  209. }
  210. }
  211. $this->save_data();
  212. return $response;
  213. }
  214. protected function refresh_token() {
  215. $endpoint = add_query_arg(
  216. array(
  217. 'refresh_token' => $this->refresh_token,
  218. 'grant_type' => 'refresh_token',
  219. ),
  220. $this->token_endpoint
  221. );
  222. $request = array(
  223. 'headers' => array(
  224. 'Authorization' => $this->get_http_authorization_header( 'basic' ),
  225. ),
  226. );
  227. $response = wp_remote_post( esc_url_raw( $endpoint ), $request );
  228. $response_code = (int) wp_remote_retrieve_response_code( $response );
  229. $response_body = wp_remote_retrieve_body( $response );
  230. $response_body = json_decode( $response_body, true );
  231. if ( WP_DEBUG and 400 <= $response_code ) {
  232. $this->log( $endpoint, $request, $response );
  233. }
  234. if ( 401 == $response_code ) { // Unauthorized
  235. $this->access_token = null;
  236. $this->refresh_token = null;
  237. } else {
  238. if ( isset( $response_body['access_token'] ) ) {
  239. $this->access_token = $response_body['access_token'];
  240. } else {
  241. $this->access_token = null;
  242. }
  243. if ( isset( $response_body['refresh_token'] ) ) {
  244. $this->refresh_token = $response_body['refresh_token'];
  245. }
  246. }
  247. $this->save_data();
  248. return $response;
  249. }
  250. protected function remote_request( $url, $request = array() ) {
  251. static $refreshed = false;
  252. $request = wp_parse_args( $request, array() );
  253. $request['headers'] = array_merge(
  254. $request['headers'],
  255. array(
  256. 'Authorization' => $this->get_http_authorization_header( 'bearer' ),
  257. )
  258. );
  259. $response = wp_remote_request( esc_url_raw( $url ), $request );
  260. if ( 401 === wp_remote_retrieve_response_code( $response )
  261. and ! $refreshed ) {
  262. $this->refresh_token();
  263. $refreshed = true;
  264. $response = $this->remote_request( $url, $request );
  265. }
  266. return $response;
  267. }
  268. protected function log( $url, $request, $response ) {
  269. wpcf7_log_remote_request( $url, $request, $response );
  270. }
  271. }