Export User Data - Version 2.1.0

Version Description

  • Excel 2007 export option added - thanks to @reyneke-vosz - https://github.com/qstudio/export-user-data/pull/5
  • Excell 2003 export option removed, as no suitable open-source library available
  • Validated as working in WP 5.5.0
  • BuddyPress support removed... sorry, but this plugin now only supports exporting data from native WordPress tables
Download this release

Release Info

Developer qlstudio
Plugin Icon wp plugin Export User Data
Version 2.1.0
Comparing to
See all releases

Code changes from version 2.0.3 to 2.1.0

Files changed (48) hide show
  1. CHANGELOG.md +170 -163
  2. export-user-data.php +200 -206
  3. library/admin/admin.php +895 -880
  4. library/admin/css/{q-report.css → q-eud.css} +133 -133
  5. library/api/admin.php +231 -231
  6. library/core/buddypress.php +99 -99
  7. library/core/config.php +88 -88
  8. library/core/core.php +426 -420
  9. library/core/excel2003.php +83 -0
  10. library/core/export.php +676 -607
  11. library/core/filters.php +59 -59
  12. library/core/helper.php +46 -49
  13. library/core/user.php +258 -239
  14. library/core/xml.php +0 -112
  15. package-lock.json +6 -0
  16. package.json +12 -0
  17. readme.md +26 -23
  18. readme.txt +200 -9
  19. vendor/PHP_XLSXWriter/.gitignore +2 -0
  20. vendor/PHP_XLSXWriter/LICENSE +20 -0
  21. vendor/PHP_XLSXWriter/README.md +100 -0
  22. vendor/PHP_XLSXWriter/composer.json +19 -0
  23. vendor/PHP_XLSXWriter/composer.lock +760 -0
  24. vendor/PHP_XLSXWriter/example-cli.php +19 -0
  25. vendor/PHP_XLSXWriter/example.php +28 -0
  26. vendor/PHP_XLSXWriter/examples/ex00-simple.php +35 -0
  27. vendor/PHP_XLSXWriter/examples/ex01-multiple-sheets.php +34 -0
  28. vendor/PHP_XLSXWriter/examples/ex02-formats.php +65 -0
  29. vendor/PHP_XLSXWriter/examples/ex03-styles.php +29 -0
  30. vendor/PHP_XLSXWriter/examples/ex04-colors.php +18 -0
  31. vendor/PHP_XLSXWriter/examples/ex05-numbers-250k-rows.php +12 -0
  32. vendor/PHP_XLSXWriter/examples/ex06-strings-250k-rows.php +23 -0
  33. vendor/PHP_XLSXWriter/examples/ex07-widths.php +13 -0
  34. vendor/PHP_XLSXWriter/examples/ex08-advanced.php +54 -0
  35. vendor/PHP_XLSXWriter/examples/ex09-autofilter.php +18 -0
  36. vendor/PHP_XLSXWriter/examples/ex10-freeze-rows-columns.php +20 -0
  37. vendor/PHP_XLSXWriter/examples/ex11-right-to-left.php +19 -0
  38. vendor/PHP_XLSXWriter/testbench/README.txt +14 -0
  39. vendor/PHP_XLSXWriter/testbench/diff-two.sh +11 -0
  40. vendor/PHP_XLSXWriter/testbench/extract.sh +36 -0
  41. vendor/PHP_XLSXWriter/testbench/openoffice.xlsx +0 -0
  42. vendor/PHP_XLSXWriter/testbench/pairs/formats.php +84 -0
  43. vendor/PHP_XLSXWriter/testbench/pairs/formats_openoffice.xlsx +0 -0
  44. vendor/PHP_XLSXWriter/testbench/pairs/test.php +84 -0
  45. vendor/PHP_XLSXWriter/testbench/test.php +33 -0
  46. vendor/PHP_XLSXWriter/testbench/test.xlsx +0 -0
  47. vendor/PHP_XLSXWriter/testbench/xlsxwriter.class.Test.php +124 -0
  48. vendor/PHP_XLSXWriter/xlsxwriter.class.php +972 -0
CHANGELOG.md CHANGED
@@ -1,163 +1,170 @@
1
- ## Changelog ##
2
-
3
- *** 2.0.3 ***
4
-
5
- * Removed remote call to jQuery UI CSS
6
- * Added extra sanitization to $_POST data
7
- * Made main class name "more" unique
8
-
9
- *** 2.0.2 ***
10
-
11
- * Cleanup and tagging for WP Repo
12
-
13
- *** 2.0.1 ***
14
-
15
- * Deprecated BuddyPress support as untested in 4 years
16
-
17
- *** 2.0.0 ***
18
-
19
- * Fork to new name Q Report
20
- * namespaced and moved to standard Q plugin setup model
21
- * buddypress support might be flaky due to limited testing
22
-
23
- *** 1.3.1 ***
24
-
25
- * Moved all internal action hooks to admin_init to allow for internal function loading
26
-
27
- *** 1.3.0 ***
28
-
29
- * Added extra data sanitization before outputting to file - thanks to Hely Shah <helyhshah@gmail.com> for te heads-up
30
-
31
- *** 1.2.8 ***
32
-
33
- * New: Added load_buddypress() methods to test for buddypress and load up if missing
34
- * New: move action hooks and priority to load later
35
- * New: Plugin no longer uses singleton model to instatiate - instead called from action hook to public function
36
- * New: added log() to debug.log file to help debugging issues
37
- * Update: jQuery datepickers pull start_of_week value from WordPress
38
- * Tested on 4.4.2
39
-
40
- *** 1.2.7 ***
41
-
42
- * Added: Spanish translation - thanks Elías Gómez Sainz ( elias@estudions.es )
43
-
44
- *** 1.2.6 ***
45
- * Update: WP 4.4.1
46
-
47
- ### 1.2.3 ###
48
- * Fix: to remove minor security loop hole
49
- * New: Added option to remove standard wp_users data from export
50
- * Fix: removed roles and groups columns from export when options hidden
51
-
52
- ### 1.2.2 ###
53
- * Minor FIxes
54
-
55
- ### 1.2.1 ###
56
- * Checked on WP 4.3.1
57
- * Moved text-domain to string in preperation for addition to translate.wordpress.org
58
- * Added Log() method to allow for debugging to WP Error Log
59
- * Added Greek translation - Thanks @Leonidas Mi
60
- * Added option to limit export by last_updated date of specific xprofile field - Thanks to @cwjordan
61
-
62
- ### 1.2.0 ###
63
- * Data stored in recursive and serialized arrays is now exported in a flat string format with safe delimiters ( ||, ||| - etc. )
64
-
65
- ### 1.1.1 ###
66
- * Removed accidently included .git files
67
-
68
- ### 1.1.0 ###
69
- * Version change to sync SVN on wordpress.org
70
-
71
- ### 1.0.4 ###
72
- * Added unserialize function with @ fallback
73
- * Removed anonymous function to allow support for PHP < 5.2
74
-
75
- ### 1.0.3 ###
76
- * Tested as working on WordPress 4.1.0.
77
-
78
- ### 1.0.2 ###
79
- * Removed get_user_meta method, as not effective.
80
- * Added registration date from and to pickers - to replace monthly <select> lists.
81
-
82
- ### 1.0.1 ###
83
- * Added recursive_implode() method to flatten data stored in arrays ( exported with keys and values divided by "|" )
84
-
85
- ### 1.0.0 ###
86
- * Reduced all get_user_meta queries to a single call to improve performance
87
- * Serialized data is now returned in it's pure stored format - not imploded or unserialized to avoid data structure loss
88
-
89
- ### 0.9.9 ###
90
- * get_uermeta renamed get_user_meta to be more consistent with WP
91
- * get_user_meta tidied up and tested on larger exports
92
- * added option to export user BP Groups
93
- * added option to export all user WP Roles
94
-
95
- ### 0.9.8 ###
96
- * added get_usermeta() to check if meta keys are unique and return an array if not
97
- * removed known_arrays() filter to allow for array data to be returned correctly - too hacky
98
-
99
- ### 0.9.7 ###
100
- * Added known_arrays() filter to allow for array data to be returned correctly
101
-
102
- ### 0.9.6 ###
103
- * Save, load and delete stored export settings - thanks to @cwjordan
104
- * Overcome memory outages on large exports - thanks to @grexican
105
- * Tested on WP 4.0.0 & BP 2.1.0
106
-
107
- ### 0.9.5 ###
108
- * BP Serialized data fixes - thanks to @nicmare & @grexican
109
- * Tested on WP 3.9.2 & BP 2.0.2
110
-
111
- ### 0.9.4 ###
112
- * BP X Profile Export Fix ( > version 2.0 )
113
-
114
- ### 0.9.3 ###
115
- * fix for hidden admin bar
116
-
117
- ### 0.9.2 ###
118
- * removed $key assignment casting to integer
119
-
120
- ### 0.9.1 ###
121
- * Tested with WP 3.9
122
- * Fix for BuddyPress 2.0 bug
123
-
124
- ### 0.9.0 ###
125
- * Moved plugin class to singleton model
126
- * Improved language handling
127
- * French translation - thanks @bastho - http://wordpress.org/support/profile/bastho
128
-
129
- ### 0.8.3 ###
130
- * clarified export limit options
131
-
132
- ### 0.8.2 ###
133
- * corrected buddypress export option - broken in 0.8.1
134
- * changed get_users arguments, in attempt to reduce memory usage
135
-
136
- ### 0.8.1 ###
137
- * Added experimental range limiter for exports
138
- * Extra input data sanitizing
139
-
140
- ### 0.8 ###
141
- * moved plugin instatiation to the WP hook: init
142
- * moved bp calls outside export loop
143
- * added extra isset calls on values in export loop to clean up error log not sets
144
-
145
- ### 0.7.8 ###
146
- * added xml template for Excel exports - thanks to phil@fixitlab.com :)
147
-
148
- ### 0.7.2 ###
149
- * fixes to allow exports without selecting extra user date from usermeta or x-profile
150
-
151
- ### 0.6.3 ###
152
- * added multiselect to pick usermeta and xprofile fields
153
-
154
- ### 0.5 ###
155
- * First public release.
156
-
157
- ## Upgrade Notice ##
158
-
159
- ### 0.6.3 ###
160
- Latest.
161
-
162
- ### 0.5 ###
163
- First release.
 
 
 
 
 
 
 
1
+ ## Changelog ##
2
+
3
+ *** 2.1.0 ***
4
+
5
+ * Excel 2007 export option added - thanks to @reyneke-vosz - https://github.com/qstudio/export-user-data/pull/5
6
+ * Excell 2003 export option removed, as no suitable open-source library available
7
+ * Validated as working in WP 5.5.0
8
+ * BuddyPress support removed... sorry, but this plugin now only supports exporting data from native WordPress tables
9
+
10
+ *** 2.0.3 ***
11
+
12
+ * Removed remote call to jQuery UI CSS
13
+ * Added extra sanitization to $_POST data
14
+ * Made main class name "more" unique
15
+
16
+ *** 2.0.2 ***
17
+
18
+ * Cleanup and tagging for WP Repo
19
+
20
+ *** 2.0.1 ***
21
+
22
+ * Deprecated BuddyPress support as untested in 4 years
23
+
24
+ *** 2.0.0 ***
25
+
26
+ * Fork to new name Q Report
27
+ * namespaced and moved to standard Q plugin setup model
28
+ * buddypress support might be flaky due to limited testing
29
+
30
+ *** 1.3.1 ***
31
+
32
+ * Moved all internal action hooks to admin_init to allow for internal function loading
33
+
34
+ *** 1.3.0 ***
35
+
36
+ * Added extra data sanitization before outputting to file - thanks to Hely Shah <helyhshah@gmail.com> for te heads-up
37
+
38
+ *** 1.2.8 ***
39
+
40
+ * New: Added load_buddypress() methods to test for buddypress and load up if missing
41
+ * New: move action hooks and priority to load later
42
+ * New: Plugin no longer uses singleton model to instatiate - instead called from action hook to public function
43
+ * New: added log() to debug.log file to help debugging issues
44
+ * Update: jQuery datepickers pull start_of_week value from WordPress
45
+ * Tested on 4.4.2
46
+
47
+ *** 1.2.7 ***
48
+
49
+ * Added: Spanish translation - thanks Elías Gómez Sainz ( elias@estudions.es )
50
+
51
+ *** 1.2.6 ***
52
+ * Update: WP 4.4.1
53
+
54
+ ### 1.2.3 ###
55
+ * Fix: to remove minor security loop hole
56
+ * New: Added option to remove standard wp_users data from export
57
+ * Fix: removed roles and groups columns from export when options hidden
58
+
59
+ ### 1.2.2 ###
60
+ * Minor FIxes
61
+
62
+ ### 1.2.1 ###
63
+ * Checked on WP 4.3.1
64
+ * Moved text-domain to string in preperation for addition to translate.wordpress.org
65
+ * Added Log() method to allow for debugging to WP Error Log
66
+ * Added Greek translation - Thanks @Leonidas Mi
67
+ * Added option to limit export by last_updated date of specific xprofile field - Thanks to @cwjordan
68
+
69
+ ### 1.2.0 ###
70
+ * Data stored in recursive and serialized arrays is now exported in a flat string format with safe delimiters ( ||, ||| - etc. )
71
+
72
+ ### 1.1.1 ###
73
+ * Removed accidently included .git files
74
+
75
+ ### 1.1.0 ###
76
+ * Version change to sync SVN on wordpress.org
77
+
78
+ ### 1.0.4 ###
79
+ * Added unserialize function with @ fallback
80
+ * Removed anonymous function to allow support for PHP < 5.2
81
+
82
+ ### 1.0.3 ###
83
+ * Tested as working on WordPress 4.1.0.
84
+
85
+ ### 1.0.2 ###
86
+ * Removed get_user_meta method, as not effective.
87
+ * Added registration date from and to pickers - to replace monthly <select> lists.
88
+
89
+ ### 1.0.1 ###
90
+ * Added recursive_implode() method to flatten data stored in arrays ( exported with keys and values divided by "|" )
91
+
92
+ ### 1.0.0 ###
93
+ * Reduced all get_user_meta queries to a single call to improve performance
94
+ * Serialized data is now returned in it's pure stored format - not imploded or unserialized to avoid data structure loss
95
+
96
+ ### 0.9.9 ###
97
+ * get_uermeta renamed get_user_meta to be more consistent with WP
98
+ * get_user_meta tidied up and tested on larger exports
99
+ * added option to export user BP Groups
100
+ * added option to export all user WP Roles
101
+
102
+ ### 0.9.8 ###
103
+ * added get_usermeta() to check if meta keys are unique and return an array if not
104
+ * removed known_arrays() filter to allow for array data to be returned correctly - too hacky
105
+
106
+ ### 0.9.7 ###
107
+ * Added known_arrays() filter to allow for array data to be returned correctly
108
+
109
+ ### 0.9.6 ###
110
+ * Save, load and delete stored export settings - thanks to @cwjordan
111
+ * Overcome memory outages on large exports - thanks to @grexican
112
+ * Tested on WP 4.0.0 & BP 2.1.0
113
+
114
+ ### 0.9.5 ###
115
+ * BP Serialized data fixes - thanks to @nicmare & @grexican
116
+ * Tested on WP 3.9.2 & BP 2.0.2
117
+
118
+ ### 0.9.4 ###
119
+ * BP X Profile Export Fix ( > version 2.0 )
120
+
121
+ ### 0.9.3 ###
122
+ * fix for hidden admin bar
123
+
124
+ ### 0.9.2 ###
125
+ * removed $key assignment casting to integer
126
+
127
+ ### 0.9.1 ###
128
+ * Tested with WP 3.9
129
+ * Fix for BuddyPress 2.0 bug
130
+
131
+ ### 0.9.0 ###
132
+ * Moved plugin class to singleton model
133
+ * Improved language handling
134
+ * French translation - thanks @bastho - http://wordpress.org/support/profile/bastho
135
+
136
+ ### 0.8.3 ###
137
+ * clarified export limit options
138
+
139
+ ### 0.8.2 ###
140
+ * corrected buddypress export option - broken in 0.8.1
141
+ * changed get_users arguments, in attempt to reduce memory usage
142
+
143
+ ### 0.8.1 ###
144
+ * Added experimental range limiter for exports
145
+ * Extra input data sanitizing
146
+
147
+ ### 0.8 ###
148
+ * moved plugin instatiation to the WP hook: init
149
+ * moved bp calls outside export loop
150
+ * added extra isset calls on values in export loop to clean up error log not sets
151
+
152
+ ### 0.7.8 ###
153
+ * added xml template for Excel exports - thanks to phil@fixitlab.com :)
154
+
155
+ ### 0.7.2 ###
156
+ * fixes to allow exports without selecting extra user date from usermeta or x-profile
157
+
158
+ ### 0.6.3 ###
159
+ * added multiselect to pick usermeta and xprofile fields
160
+
161
+ ### 0.5 ###
162
+ * First public release.
163
+
164
+ ## Upgrade Notice ##
165
+
166
+ ### 0.6.3 ###
167
+ Latest.
168
+
169
+ ### 0.5 ###
170
+ First release.
export-user-data.php CHANGED
@@ -1,206 +1,200 @@
1
- <?php
2
-
3
- /*
4
- * Plugin Name: Export User Date
5
- * Description: Export User data and metadata.
6
- * Version: 2.0.3
7
- * Author: Q Studio
8
- * Author URI: http://qstudio.us/
9
- * License: GPL2
10
- * Class: q_export_user_data
11
- * Text Domain: q-export-user-data
12
- * GitHub Plugin URI: qstudio/q-export-user-data
13
- */
14
-
15
- /*
16
- This plugin will add a "Report" sub menu to the users tab and provide a screen which lists a sent of pre-built report buttons - in some cases with options or filtered by program
17
- Exports will print to the screen first - and then have a "Download" button to export csv / xls formatted data
18
-
19
- - rebuild export user data with filters, defaults and tweaks to make it most relevant to Club Data ##
20
- - read reports on WP and address all issues in release ##
21
- - move all custom filters / hacks to filter system - controlled from q_club ( or functions.php for most theme based controls ) ##
22
- */
23
-
24
- defined( 'ABSPATH' ) OR exit;
25
-
26
- if ( ! class_exists( 'q_export_user_data' ) ) {
27
-
28
- // instatiate plugin via WP plugins_loaded - init is too late for CPT ##
29
- add_action( 'init', array ( 'q_export_user_data', 'get_instance' ), 1000000 );
30
-
31
- class q_export_user_data {
32
-
33
- // Refers to a single instance of this class. ##
34
- private static $instance = null;
35
-
36
- // Plugin Settings
37
- const version = '2.0.3';
38
- static $debug = true;
39
- const text_domain = 'q-export-user-data'; // for translation ##
40
-
41
- /* properties */
42
- public static $q_report_exports = ''; // export settings ##
43
- public static $usermeta_saved_fields = array();
44
- public static $bp_fields_saved_fields = array();
45
- public static $bp_fields_update_time_saved_fields = array();
46
- public static $role = '';
47
- public static $roles = '0';
48
- public static $user_fields = '1';
49
- public static $groups = '0';
50
- public static $start_date = '';
51
- public static $end_date = '';
52
- public static $limit_offset = '';
53
- public static $limit_total = '';
54
- public static $updated_since_date = '';
55
- public static $field_updated_since = '';
56
- public static $format = '';
57
- public static $bp_data_available = false;
58
- public static $allowed_tags = '';
59
-
60
- // api ##
61
- public static $api_admin_fields = false;
62
-
63
- /**
64
- * Creates or returns an instance of this class.
65
- *
66
- * @return Foo A single instance of this class.
67
- */
68
- public static function get_instance()
69
- {
70
-
71
- if ( null == self::$instance ) {
72
- self::$instance = new self;
73
- }
74
-
75
- return self::$instance;
76
-
77
- }
78
-
79
-
80
- /**
81
- * Instatiate Class
82
- *
83
- * @since 0.2
84
- * @return void
85
- */
86
- private function __construct()
87
- {
88
-
89
- // activation ##
90
- register_activation_hook( __FILE__, array ( $this, 'register_activation_hook' ) );
91
-
92
- // deactvation ##
93
- register_deactivation_hook( __FILE__, array ( $this, 'register_deactivation_hook' ) );
94
-
95
- // set text domain ##
96
- add_action( 'init', array( $this, 'load_plugin_textdomain' ), 1 );
97
-
98
- // load libraries ##
99
- self::load_libraries();
100
-
101
- }
102
-
103
-
104
- // the form for sites have to be 1-column-layout
105
- public function register_activation_hook() {
106
-
107
- \add_option( 'q_report_configured' );
108
-
109
- // flush rewrites ##
110
- #global $wp_rewrite;
111
- #$wp_rewrite->flush_rules();
112
-
113
- }
114
-
115
-
116
- public function register_deactivation_hook() {
117
-
118
- \delete_option( 'q_report_configured' );
119
-
120
- }
121
-
122
-
123
-
124
- /**
125
- * Load Text Domain for translations
126
- *
127
- * @since 1.7.0
128
- *
129
- */
130
- public function load_plugin_textdomain()
131
- {
132
-
133
- // set text-domain ##
134
- $domain = self::text_domain;
135
-
136
- // The "plugin_locale" filter is also used in load_plugin_textdomain()
137
- $locale = apply_filters('plugin_locale', get_locale(), $domain);
138
-
139
- // try from global WP location first ##
140
- load_textdomain( $domain, WP_LANG_DIR.'/plugins/'.$domain.'-'.$locale.'.mo' );
141
-
142
- // try from plugin last ##
143
- load_plugin_textdomain( $domain, FALSE, plugin_dir_path( __FILE__ ).'library/languages/' );
144
-
145
- }
146
-
147
-
148
-
149
- /**
150
- * Get Plugin URL
151
- *
152
- * @since 0.1
153
- * @param string $path Path to plugin directory
154
- * @return string Absoulte URL to plugin directory
155
- */
156
- public static function get_plugin_url( $path = '' )
157
- {
158
-
159
- return plugins_url( $path, __FILE__ );
160
-
161
- }
162
-
163
-
164
- /**
165
- * Get Plugin Path
166
- *
167
- * @since 0.1
168
- * @param string $path Path to plugin directory
169
- * @return string Absoulte URL to plugin directory
170
- */
171
- public static function get_plugin_path( $path = '' )
172
- {
173
-
174
- return plugin_dir_path( __FILE__ ).$path;
175
-
176
- }
177
-
178
-
179
- /**
180
- * Load Libraries
181
- *
182
- * @since 2.0
183
- */
184
- private static function load_libraries()
185
- {
186
-
187
- // methods ##
188
- require_once self::get_plugin_path( 'library/core/helper.php' );
189
- require_once self::get_plugin_path( 'library/core/core.php' );
190
- require_once self::get_plugin_path( 'library/core/user.php' );
191
- require_once self::get_plugin_path( 'library/core/buddypress.php' );
192
- require_once self::get_plugin_path( 'library/core/xml.php' );
193
- require_once self::get_plugin_path( 'library/core/export.php' );
194
- require_once self::get_plugin_path( 'library/core/filters.php' );
195
-
196
- // api ##
197
- require_once self::get_plugin_path( 'library/api/admin.php' );
198
-
199
- // backend ##
200
- require_once self::get_plugin_path( 'library/admin/admin.php' );
201
-
202
- }
203
-
204
- }
205
-
206
- }
1
+ <?php
2
+
3
+ /*
4
+ * Plugin Name: Export User Date
5
+ * Description: Export User data and metadata.
6
+ * Version: 2.1.0
7
+ * Author: Q Studio
8
+ * Author URI: http://qstudio.us/
9
+ * License: GPL2
10
+ * Class: q_export_user_data
11
+ * Text Domain: q-export-user-data
12
+ * GitHub Plugin URI: qstudio/export-user-data
13
+ */
14
+
15
+ defined( 'ABSPATH' ) OR exit;
16
+
17
+ if ( ! class_exists( 'q_export_user_data' ) ) {
18
+
19
+ // instatiate plugin via WP plugins_loaded - init is too late for CPT ##
20
+ add_action( 'init', array ( 'q_export_user_data', 'get_instance' ), 1000000 );
21
+
22
+ class q_export_user_data {
23
+
24
+ // Refers to a single instance of this class. ##
25
+ private static $instance = null;
26
+
27
+ // Plugin Settings
28
+ const version = '2.1.0';
29
+ static $debug = false;
30
+ const text_domain = 'q-export-user-data'; // for translation ##
31
+
32
+ /* properties */
33
+ public static $q_eud_exports = ''; // export settings ##
34
+ public static $usermeta_saved_fields = array();
35
+ public static $bp_fields_saved_fields = array();
36
+ public static $bp_fields_update_time_saved_fields = array();
37
+ public static $role = '';
38
+ public static $roles = '0';
39
+ public static $user_fields = '1';
40
+ public static $groups = '0';
41
+ public static $start_date = '';
42
+ public static $end_date = '';
43
+ public static $limit_offset = '';
44
+ public static $limit_total = '';
45
+ public static $updated_since_date = '';
46
+ public static $field_updated_since = '';
47
+ public static $format = '';
48
+ public static $bp_data_available = false;
49
+ public static $allowed_tags = '';
50
+
51
+ // api ##
52
+ public static $api_admin_fields = false;
53
+
54
+ /**
55
+ * Creates or returns an instance of this class.
56
+ *
57
+ * @return Foo A single instance of this class.
58
+ */
59
+ public static function get_instance()
60
+ {
61
+
62
+ if ( null == self::$instance ) {
63
+ self::$instance = new self;
64
+ }
65
+
66
+ return self::$instance;
67
+
68
+ }
69
+
70
+
71
+ /**
72
+ * Instatiate Class
73
+ *
74
+ * @since 0.2
75
+ * @return void
76
+ */
77
+ private function __construct()
78
+ {
79
+
80
+ // activation ##
81
+ register_activation_hook( __FILE__, array ( $this, 'register_activation_hook' ) );
82
+
83
+ // deactvation ##
84
+ register_deactivation_hook( __FILE__, array ( $this, 'register_deactivation_hook' ) );
85
+
86
+ // set text domain ##
87
+ add_action( 'init', array( $this, 'load_plugin_textdomain' ), 1 );
88
+
89
+ // load libraries ##
90
+ self::load_libraries();
91
+
92
+ }
93
+
94
+
95
+ // the form for sites have to be 1-column-layout
96
+ public function register_activation_hook() {
97
+
98
+ \add_option( 'q_eud_configured' );
99
+
100
+ // flush rewrites ##
101
+ #global $wp_rewrite;
102
+ #$wp_rewrite->flush_rules();
103
+
104
+ }
105
+
106
+
107
+ public function register_deactivation_hook() {
108
+
109
+ \delete_option( 'q_eud_configured' );
110
+
111
+ }
112
+
113
+
114
+
115
+ /**
116
+ * Load Text Domain for translations
117
+ *
118
+ * @since 1.7.0
119
+ *
120
+ */
121
+ public function load_plugin_textdomain()
122
+ {
123
+
124
+ // set text-domain ##
125
+ $domain = self::text_domain;
126
+
127
+ // The "plugin_locale" filter is also used in load_plugin_textdomain()
128
+ $locale = apply_filters('plugin_locale', get_locale(), $domain);
129
+
130
+ // try from global WP location first ##
131
+ load_textdomain( $domain, WP_LANG_DIR.'/plugins/'.$domain.'-'.$locale.'.mo' );
132
+
133
+ // try from plugin last ##
134
+ load_plugin_textdomain( $domain, FALSE, plugin_dir_path( __FILE__ ).'library/languages/' );
135
+
136
+ }
137
+
138
+
139
+
140
+ /**
141
+ * Get Plugin URL
142
+ *
143
+ * @since 0.1
144
+ * @param string $path Path to plugin directory
145
+ * @return string Absoulte URL to plugin directory
146
+ */
147
+ public static function get_plugin_url( $path = '' )
148
+ {
149
+
150
+ return plugins_url( $path, __FILE__ );
151
+
152
+ }
153
+
154
+
155
+ /**
156
+ * Get Plugin Path
157
+ *
158
+ * @since 0.1
159
+ * @param string $path Path to plugin directory
160
+ * @return string Absoulte URL to plugin directory
161
+ */
162
+ public static function get_plugin_path( $path = '' )
163
+ {
164
+
165
+ return plugin_dir_path( __FILE__ ).$path;
166
+
167
+ }
168
+
169
+
170
+ /**
171
+ * Load Libraries
172
+ *
173
+ * @since 2.0
174
+ */
175
+ private static function load_libraries()
176
+ {
177
+
178
+ // vendor ##
179
+ require_once self::get_plugin_path( 'vendor/PHP_XLSXWriter/xlsxwriter.class.php' );
180
+
181
+ // methods ##
182
+ require_once self::get_plugin_path( 'library/core/helper.php' );
183
+ require_once self::get_plugin_path( 'library/core/core.php' );
184
+ require_once self::get_plugin_path( 'library/core/user.php' );
185
+ require_once self::get_plugin_path( 'library/core/buddypress.php' );
186
+ // require_once self::get_plugin_path( 'library/core/excel2003.php' );
187
+ require_once self::get_plugin_path( 'library/core/export.php' );
188
+ require_once self::get_plugin_path( 'library/core/filters.php' );
189
+
190
+ // api ##
191
+ require_once self::get_plugin_path( 'library/api/admin.php' );
192
+
193
+ // backend ##
194
+ require_once self::get_plugin_path( 'library/admin/admin.php' );
195
+
196
+ }
197
+
198
+ }
199
+
200
+ }
 
 
 
 
 
 
library/admin/admin.php CHANGED
@@ -1,880 +1,895 @@
1
- <?php
2
-
3
- namespace q\report\admin;
4
-
5
- use q\report\core\core as core;
6
- use q\report\core\helper as helper;
7
- use q\report\core\user as user;
8
- use q\report\core\buddypress as buddypress;
9
- use q\report\api\admin as api_admin;
10
-
11
- // load it up ##
12
- \q\report\admin\admin::run();
13
-
14
- class admin extends \q_export_user_data {
15
-
16
- public static function run()
17
- {
18
-
19
- #global $pagenow;
20
-
21
- if ( \is_admin() ) {
22
-
23
- // add export menu inside admin ##
24
- \add_action( 'admin_menu', array( get_class(), 'add_menu' ) );
25
-
26
- // UI style and functionality ##
27
- \add_action( 'admin_enqueue_scripts', array( get_class(), 'admin_enqueue_scripts' ), 1 );
28
- \add_action( 'admin_footer', array( get_class(), 'jquery' ), 100000 );
29
- \add_action( 'admin_footer', array( get_class(), 'css' ), 100000 );
30
-
31
- }
32
-
33
- }
34
-
35
-
36
-
37
- /**
38
- * Add administration menus
39
- *
40
- * @since 0.1
41
- **/
42
- public static function add_menu()
43
- {
44
-
45
- add_users_page (
46
- __( 'Export User Data', 'q-export-user-data' ),
47
- __( 'Export User Data', 'q-export-user-data' ),
48
- \apply_filters( 'q/report/admin_capability', 'list_users' ),
49
- 'q-export-user-data',
50
- array(
51
- get_class(),
52
- 'admin_page'
53
- )
54
- );
55
-
56
- }
57
-
58
-
59
- /**
60
- * Content of the admin page
61
- *
62
- * @since 0.1
63
- */
64
- public static function admin_page()
65
- {
66
-
67
- // quick security check ##
68
- if ( ! \current_user_can( \apply_filters( 'q/report/admin_capability', 'list_users' ) ) ) {
69
-
70
- \wp_die( __( 'You do not have sufficient permissions to access this page.', 'q-export-user-data' ) );
71
-
72
- }
73
-
74
- // Save settings button was pressed ##
75
- if (
76
- isset( $_POST['save_export'] )
77
- && \check_admin_referer( 'q-report-admin-page', '_wpnonce-q-report-admin-page' )
78
- ) {
79
-
80
- // start with an empty variable ##
81
- $save_export = "";
82
-
83
- if ( ! empty( $_POST['save_new_export_name'] ) ) {
84
-
85
- // assign value ##
86
- $save_export = $_POST['save_new_export_name'];
87
-
88
- } elseif ( ! empty( $_POST['export_name'] ) ) {
89
-
90
- $save_export = $_POST['export_name'];
91
-
92
- }
93
-
94
- // clean up $save_export ##
95
- $save_export = \sanitize_text_field( $save_export );
96
-
97
- // Build array of $options to save and save them ##
98
- if ( isset( $save_export ) ) {
99
-
100
- // prepare all array values ##
101
- $usermeta =
102
- isset( $_POST['usermeta'] ) ?
103
- \sanitize_text_field( $_POST['usermeta'] ):
104
- '' ;
105
- $bp_fields =
106
- isset( $_POST['bp_fields'] ) ?
107
- array_map( 'sanitize_text_field', $_POST['bp_fields'] ) :
108
- '' ;
109
- $bp_fields_update =
110
- isset( $_POST['bp_fields_update_time'] ) ?
111
- array_map( 'sanitize_text_field', $_POST['bp_fields_update_time'] ) :
112
- '' ;
113
- $format =
114
- isset( $_POST['format'] ) ?
115
- \sanitize_text_field( $_POST['format'] ) :
116
- '' ;
117
- $role =
118
- isset( $_POST['role'] ) ?
119
- \sanitize_text_field( $_POST['role'] ) :
120
- '' ;
121
- $roles =
122
- isset( $_POST['roles'] ) ?
123
- \sanitize_text_field( $_POST['roles'] ) :
124
- '' ;
125
- $user_fields =
126
- isset( $_POST['user_fields'] ) ?
127
- array_map( 'sanitize_text_field', $_POST['user_fields'] ) :
128
- '0' ;
129
- $groups =
130
- isset( $_POST['groups'] ) ?
131
- \sanitize_text_field( $_POST['groups'] ) :
132
- '0' ;
133
- $start_date =
134
- isset( $_POST['start_date'] ) ?
135
- \sanitize_text_field( $_POST['start_date'] ) :
136
- '' ;
137
- $end_date =
138
- isset( $_POST['end_date'] ) ?
139
- \sanitize_text_field( $_POST['end_date'] ) :
140
- '' ;
141
- $limit_offset =
142
- isset( $_POST['limit_offset'] ) ?
143
- \sanitize_text_field( $_POST['limit_offset'] ) :
144
- '' ;
145
- $limit_total =
146
- isset( $_POST['limit_total'] ) ?
147
- \sanitize_text_field( $_POST['limit_total'] ) :
148
- '' ;
149
- $updated_since_date =
150
- isset( $_POST['updated_since_date'] ) ?
151
- \sanitize_text_field( $_POST['updated_since_date'] ) :
152
- '' ;
153
- $field_updated_since =
154
- isset( $_POST['bp_field_updated_since'] ) ?
155
- array_map( 'sanitize_text_field', $_POST['bp_field_updated_since'] ) :
156
- '';
157
-
158
- // assign all values to an array ##
159
- $save_array = array (
160
- 'usermeta_saved_fields' => $usermeta,
161
- 'bp_fields_saved_fields' => $bp_fields,
162
- 'bp_fields_update_time_saved_fields' => $bp_fields_update,
163
- 'role' => $role,
164
- 'roles' => $roles,
165
- 'user_fields' => $user_fields,
166
- 'groups' => $groups,
167
- 'start_date' => $start_date,
168
- 'end_date' => $end_date,
169
- 'limit_offset' => $limit_offset,
170
- 'limit_total' => $limit_total,
171
- 'updated_since_date' => $updated_since_date,
172
- 'field_updated_since' => $field_updated_since,
173
- 'format' => $format
174
- );
175
-
176
- // store the options, for next load ##
177
- user::set_user_options( $save_export, $save_array );
178
-
179
- // Display the settings the user just saved instead of blanking the form ##
180
- $_POST['load_export'] = 'Load Settings';
181
- $_POST['export_name'] = $save_export;
182
-
183
- }
184
-
185
- }
186
-
187
- // Load settings button was pressed ( or option saved and $_POST variables hijacked )##
188
- if (
189
- isset( $_POST['load_export'] )
190
- && isset( $_POST['export_name'] )
191
- && \check_admin_referer( 'q-report-admin-page', '_wpnonce-q-report-admin-page' )
192
- ) {
193
-
194
- user::get_user_options_by_export( \sanitize_text_field( $_POST['export_name'] ) );
195
-
196
- }
197
-
198
- // Delete settings button was pressed ##
199
- if (
200
- isset( $_POST['delete_export'] )
201
- && isset( $_POST['export_name'] )
202
- && \check_admin_referer( 'q-report-admin-page', '_wpnonce-q-report-admin-page' )
203
- ) {
204
-
205
- user::delete_user_options( \sanitize_text_field( $_POST['export_name'] ) );
206
-
207
- }
208
-
209
- ?>
210
- <div class="wrap">
211
- <h2><?php \_e( 'Export User Data', 'q-export-user-data' ); ?></h2>
212
- <?php
213
-
214
- // nothing happening? ##
215
- if ( isset( $_GET['error'] ) ) {
216
- echo '<div class="updated"><p><strong>' . \__( 'No users found.', 'q-export-user-data' ) . '</strong></p></div>';
217
- }
218
-
219
- ?>
220
- <form method="post" action="" enctype="multipart/form-data">
221
- <?php \wp_nonce_field( 'q-report-admin-page', '_wpnonce-q-report-admin-page' ); ?>
222
- <table class="form-table">
223
- <?php
224
-
225
- // allow admin to select user meta fields to export ##
226
- global $wpdb;
227
-
228
- // filterable SQL ##
229
- $meta_keys = \apply_filters(
230
- 'q/report/admin/sql',
231
- $wpdb->get_results( "SELECT distinct(meta_key) FROM $wpdb->usermeta" )
232
- );
233
-
234
- // filterable sort ##
235
- \apply_filters(
236
- 'q/report/admin/sort',
237
- asort( $meta_keys )
238
- );
239
-
240
- // get meta_key value from object ##
241
- $meta_keys = \wp_list_pluck( $meta_keys, 'meta_key' );
242
-
243
- // allow array to be filtered ##
244
- $meta_keys_common = \apply_filters( 'q/report/admin/meta_keys_common', [] );
245
-
246
- // test array ##
247
- #helper::log( $meta_keys );
248
- #helper::log( $meta_keys_common );
249
-
250
- // check if we got anything ? ##
251
- if ( $meta_keys ) {
252
-
253
- ?>
254
- <tr valign="top">
255
- <th scope="row">
256
- <label for="q_report_usermeta"><?php \_e( 'User Meta Fields', 'q-export-user-data' ); ?></label>
257
- <p class="filter" style="margin: 10px 0 0;">
258
- <?php \_e('Filter', 'q-export-user-data'); ?>: <a href="#" class="usermeta-all"><?php \_e('All', 'q-export-user-data'); ?></a> | <a href="#" class="usermeta-common"><?php \_e('Common', 'q-export-user-data'); ?></a>
259
- </p>
260
- <p class="filter" style="margin: 10px 0 0;">
261
- <?php \_e('Select', 'q-export-user-data'); ?>: <a href="#" class="select-all"><?php \_e('All', 'q-export-user-data'); ?></a> | <a href="#" class="select-none"><?php \_e('None', 'q-export-user-data'); ?></a>
262
- </p>
263
- </th>
264
- <td>
265
- <select multiple="multiple" id="usermeta" name="usermeta[]">
266
- <?php
267
-
268
- foreach ( $meta_keys as $key ) {
269
-
270
- // filter key displayed ##
271
- $display_key = \apply_filters( 'q/report/admin/display_key', $key );
272
-
273
- // class ##
274
- $usermeta_class = 'normal';
275
-
276
- foreach ( $meta_keys_common as $drop ) {
277
-
278
- #helper::log( 'Checking: '.$drop );
279
-
280
- if ( strpos( $key, $drop ) !== false ) {
281
-
282
- #helper::log( 'Checking: '.$key );
283
-
284
- // https://wordpress.org/support/topic/bugfix-numbers-in-export-headers?replies=1
285
- // removed $key = assignment, as not required ##
286
- if ( ( array_search( $key, $meta_keys ) ) !== false ) {
287
-
288
- #helper::log( 'Found: '.$key );
289
-
290
- $usermeta_class = 'common';
291
-
292
- }
293
-
294
- }
295
-
296
- }
297
-
298
- // print key ##
299
- echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."' class='".$usermeta_class."'>$display_key</option>";
300
-
301
- }
302
- ?>
303
- </select>
304
- <p class="description"><?php
305
- printf(
306
- \__( 'Select the user meta keys to export, use the filters to simplify the list.', 'q-export-user-data' )
307
- );
308
- ?></p>
309
- </td>
310
- </tr>
311
- <?php
312
-
313
- } // meta_keys found ##
314
-
315
- ?>
316
- <?php
317
-
318
- // buddypress x profile data ##
319
- if ( $bp_fields = buddypress::get_fields() ) {
320
-
321
- ?>
322
- <tr valign="top">
323
- <th scope="row">
324
- <label for="q_report_xprofile"><?php \_e( 'BP xProfile Fields', 'q-export-user-data' ); ?></label>
325
- <p class="filter" style="margin: 10px 0 0;">
326
- <?php \_e('Select', 'q-export-user-data'); ?>: <a href="#" class="select-all"><?php \_e('All', 'q-export-user-data'); ?></a> | <a href="#" class="select-none"><?php \_e('None', 'q-export-user-data'); ?></a>
327
- </p>
328
- </th>
329
- <td>
330
- <select multiple="multiple" id="bp_fields" name="bp_fields[]">
331
- <?php
332
-
333
- foreach ( $bp_fields as $key ) {
334
-
335
- // print key ##
336
- echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."'>$key</option>";
337
-
338
- }
339
-
340
- ?>
341
- </select>
342
- <p class="description"><?php
343
- printf(
344
- \__( 'Select the BuddyPress XProfile keys to export', 'q-export-user-data' )
345
- );
346
- ?></p>
347
- </td>
348
- </tr>
349
- <?php
350
-
351
- // allow export of update times ##
352
-
353
- ?>
354
- <tr valign="top" class="toggleable">
355
- <th scope="row">
356
- <label for="q_report_xprofile"><?php \_e( 'BP xProfile Fields Update Time', 'q-export-user-data' ); ?></label>
357
- <p class="filter" style="margin: 10px 0 0;">
358
- <?php \_e('Select', 'q-export-user-data'); ?>: <a href="#" class="select-all"><?php \_e('All', 'q-export-user-data'); ?></a> | <a href="#" class="select-none"><?php _e('None', 'q-export-user-data'); ?></a>
359
- </p>
360
- </th>
361
- <td>
362
- <select multiple="multiple" id="bp_fields_update_time" name="bp_fields_update_time[]">
363
- <?php
364
-
365
- foreach ( $bp_fields as $key ) {
366
-
367
- echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."'>$key</option>";
368
-
369
- }
370
-
371
- ?>
372
- </select>
373
- <p class="description"><?php
374
- printf(
375
- \__( 'Select the BuddyPress XProfile keys updated dates to export', 'q-export-user-data' )
376
- );
377
- ?></p>
378
- </td>
379
- </tr>
380
-
381
- <tr valign="top" class="toggleable">
382
- <th scope="row"><label for="groups"><?php \_e( 'BP User Groups', 'q-export-user-data' ); ?></label></th>
383
- <td>
384
- <input id='groups' type='checkbox' name='groups' value='1' <?php \checked( isset ( self::$groups ) ? intval ( self::$groups ) : '', 1 ); ?> />
385
- <p class="description"><?php
386
- printf(
387
- \__( 'Include BuddyPress Group Data. <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
388
- , \esc_html('https://codex.buddypress.org/buddypress-components-and-features/groups/')
389
- , 'Codex'
390
- );
391
- ?></p>
392
- </td>
393
- </tr>
394
- <?php
395
-
396
- } // BP installed and active ##
397
-
398
- ?>
399
- <tr valign="top" class="toggleable">
400
- <th scope="row"><label for="user_fields"><?php \_e( 'Standard User Fields', 'q-export-user-data' ); ?></label></th>
401
- <td>
402
- <input id='user_fields' type='checkbox' name='user_fields' value='1' <?php \checked( isset ( self::$user_fields ) ? intval ( self::$user_fields ) : '', 1 ); ?> />
403
- <p class="description"><?php
404
-
405
- #self::log( 'user_fields: '.self::$user_fields );
406
- #echo 'user_fields: '. self::$user_fields;
407
-
408
- printf(
409
- \__( 'Include Standard user profile fields, such as user_login. <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
410
- , \esc_html('https://codex.wordpress.org/Database_Description#Table:_wp_users')
411
- , 'Codex'
412
- );
413
-
414
- ?></p>
415
- </td>
416
- </tr>
417
-
418
- <tr valign="top" class="toggleable">
419
- <th scope="row"><label for="q_report_users_role"><?php \_e( 'Role', 'q-export-user-data' ); ?></label></th>
420
- <td>
421
- <select name="role" id="q_report_users_role">
422
- <?php
423
-
424
- echo '<option value="">' . \__( 'All Roles', 'q-export-user-data' ) . '</option>';
425
-
426
- global $wp_roles;
427
-
428
- foreach ( $wp_roles->role_names as $role => $name ) {
429
-
430
- if ( isset ( self::$role ) && ( self::$role == $role ) ) {
431
-
432
- echo "\n\t<option selected value='" . \esc_attr( $role ) . "'>$name</option>";
433
-
434
- } else {
435
-
436
- echo "\n\t<option value='" . \esc_attr( $role ) . "'>$name</option>";
437
-
438
- }
439
- }
440
-
441
-
442
- ?>
443
- </select>
444
- <p class="description"><?php
445
- printf(
446
- \__( 'Filter the exported users by a WordPress Role. <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
447
- , \esc_html('http://codex.wordpress.org/Roles_and_Capabilities')
448
- , 'Codex'
449
- );
450
- ?></p>
451
- </td>
452
- </tr>
453
-
454
- <tr valign="top" class="toggleable">
455
- <th scope="row"><label for="roles"><?php \_e( 'User Roles', 'q-export-user-data' ); ?></label></th>
456
- <td>
457
- <input id='roles' type='checkbox' name='roles' value='1' <?php \checked( isset ( self::$roles ) ? intval ( self::$roles ) : '', 1 ); ?> />
458
- <p class="description"><?php
459
- printf(
460
- \__( 'Include all of the users <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
461
- , \esc_html('http://codex.wordpress.org/Roles_and_Capabilities')
462
- , 'Roles'
463
- );
464
- ?></p>
465
- </td>
466
- </tr>
467
-
468
- <tr valign="top" class="toggleable">
469
- <th scope="row"><label><?php \_e( 'Registered', 'q-export-user-data' ); ?></label></th>
470
- <td>
471
- <input type="text" id="q_report_users_start_date" name="start_date" value="<?php echo self::$start_date; ?>" class="start-datepicker" />
472
- <input type="text" id="q_report_users_end_date" name="end_date" value="<?php echo self::$end_date; ?>" class="end-datepicker" />
473
- <p class="description"><?php
474
- printf(
475
- \__( 'Pick a start and end user registration date to limit the results.', 'q-export-user-data' )
476
- );
477
- ?></p>
478
- </td>
479
- </tr>
480
-
481
- <tr valign="top" class="toggleable">
482
- <th scope="row"><label><?php \_e( 'Limit Range', 'q-export-user-data' ); ?></label></th>
483
- <td>
484
- <input name="limit_offset" type="text" id="q_report_users_limit_offset" value="<?php echo( self::$limit_offset ); ?>" class="regular-text code numeric" style="width: 136px;" placeholder="<?php _e( 'Offset', 'q-export-user-data' ); ?>">
485
- <input name="limit_total" type="text" id="q_report_users_limit_total" value="<?php echo ( self::$limit_total ); ?>" class="regular-text code numeric" style="width: 136px;" placeholder="<?php _e( 'Total', 'q-export-user-data' ); ?>">
486
- <p class="description"><?php
487
- printf(
488
- \__( 'Enter an offset start number and a total number of users to export. <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
489
- , \esc_html('http://codex.wordpress.org/Function_Reference/get_users#Parameters')
490
- , 'Codex'
491
- );
492
- ?></p>
493
- </td>
494
- </tr>
495
- <?php
496
-
497
- // buddypress x profile data ##
498
- if ( $bp_fields = buddypress::get_fields() ) {
499
-
500
- ?>
501
- <tr valign="top" class="toggleable">
502
- <th scope="row"><label><?php \_e( 'Updated Since', 'q-export-user-data' ); ?></label></th>
503
- <td>
504
- <input type="text" id="q_report_updated_since_date" name="updated_since_date" value="<?php echo self::$updated_since_date; ?>" class="updated-datepicker" />
505
- <select id="bp_field_updated_since" name="bp_field_updated_since">
506
- <?php
507
-
508
- foreach ( $bp_fields as $key ) {
509
-
510
- if ( self::$field_updated_since == $key ) {
511
-
512
- echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."' selected>$key</option>";
513
-
514
- } else {
515
-
516
- echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."'>$key</option>";
517
-
518
- }
519
-
520
- }
521
-
522
- ?>
523
- </select>
524
-
525
- <p class="description"><?php
526
- printf(
527
- \__( 'Limit the results to users who have updated this extended profile field after this date.', 'q-export-user-data' )
528
- );
529
- ?></p>
530
- </td>
531
- </tr>
532
- <?php
533
-
534
- } // bp date ##
535
-
536
- // pull in extra export options from api ##
537
- if ( $api_fields = \apply_filters( 'q/report/api/admin/fields', [] ) ) {
538
-
539
- foreach( $api_fields as $field ) {
540
-
541
- api_admin::render( $field );
542
-
543
- }
544
-
545
- }
546
-
547
- ?>
548
- <tr valign="top">
549
- <th scope="row"><label for="q_report_users_format"><?php \_e( 'Format', 'q-export-user-data' ); ?></label></th>
550
- <td>
551
- <select name="format" id="q_report_users_format">
552
- <?php
553
- if ( isset ( self::$format ) && ( self::$format == 'excel' ) ) {
554
-
555
- echo '<option selected value="excel">' . __( 'Excel', 'q-export-user-data' ) . '</option>';
556
-
557
- } else {
558
-
559
- echo '<option value="excel">' . __( 'Excel', 'q-export-user-data' ) . '</option>';
560
-
561
- }
562
-
563
- if ( isset ( self::$format ) && ( self::$format == 'csv' ) ) {
564
-
565
- echo '<option selected value="csv">' . __( 'CSV', 'q-export-user-data' ) . '</option>';
566
-
567
- } else {
568
-
569
- echo '<option value="csv">' . __( 'CSV', 'q-export-user-data' ) . '</option>';
570
-
571
- }
572
- ?>
573
- </select>
574
- <p class="description"><?php
575
- printf(
576
- \__( 'Select the format for the export file.', 'q-export-user-data' )
577
- );
578
- ?></p>
579
- </td>
580
- </tr>
581
-
582
- <tr valign="top" class="remember">
583
- <th scope="row"><label for="q_report_save_options"><?php \_e( 'Stored Options', 'q-export-user-data' ); ?></label></th>
584
- <td>
585
-
586
- <div class="row">
587
- <input type="text" class="regular-text" name="save_new_export_name" id="q_report_save_options_new_export" placeholder="<?php \_e( 'Export Name', 'q-export-user-data' ); ?>" value="<?php echo isset( $_POST['export_name'] ) ? \sanitize_text_field( $_POST['export_name'] ) : '' ; ?>">
588
- <input type="submit" id="save_export" class="button-primary" name="save_export" value="<?php \_e( 'Save', 'q-export-user-data' ); ?>" />
589
- </div>
590
- <?php
591
-
592
- // check if the user has any saved exports ##
593
- if ( user::get_user_options() ) {
594
-
595
- ?>
596
- <div class="row">
597
- <select name="export_name" id="q_report_save_options" class="regular-text">
598
- <?php
599
-
600
- // loop over each saved export ##
601
- foreach( user::get_user_options() as $export ) {
602
-
603
- // select Loaded export name, if selected ##
604
- if (
605
- isset( $_POST['load_export'] )
606
- && isset( $_POST['export_name'] )
607
- && ( \sanitize_text_field( $_POST['export_name'] ) == $export )
608
- ) {
609
-
610
- echo "<option selected value='$export'>".$export."</option>";
611
-
612
- // just list previous export name ##
613
- } else {
614
-
615
- echo "<option value='$export'>".$export."</option>";
616
-
617
- }
618
-
619
- }
620
-
621
- ?>
622
- </select>
623
-
624
- <input type="submit" id="load_export" class="button-primary" name="load_export" value="<?php _e( 'Load', 'q-export-user-data' ); ?>" />
625
- <input type="submit" id="delete_export" class="button-primary" name="delete_export" value="<?php _e( 'Delete', 'q-export-user-data' ); ?>" />
626
- <?php
627
-
628
- }
629
-
630
- ?>
631
- </div>
632
- <p class="description"><?php \_e( 'Save, load or delete your stored export options.', 'q-export-user-data' ); ?></p>
633
-
634
- </td>
635
- </tr>
636
-
637
- <tr valign="top">
638
- <th scope="row">
639
- <label for="q_report_xprofile"><?php \_e( 'Advanced Options', 'q-export-user-data' ); ?></label>
640
- </th>
641
- <td>
642
- <div class="toggle">
643
- <a href="#"><?php \_e( 'Show', 'q-export-user-data' ); ?></a>
644
- </div>
645
- </td>
646
- </tr>
647
-
648
- </table>
649
- <p class="submit">
650
- <input type="hidden" name="_wp_http_referer" value="<?php echo \esc_url( $_SERVER['REQUEST_URI'] ); ?>" />
651
- <input type="submit" class="button-primary" value="<?php \_e( 'Run Export', 'q-export-user-data' ); ?>" />
652
- </p>
653
- </form>
654
- </div>
655
-
656
- <?php
657
- }
658
-
659
-
660
-
661
- /**
662
- * style and interaction
663
- */
664
- public static function admin_enqueue_scripts( $hook )
665
- {
666
-
667
- // load the scripts on only the plugin admin page ##
668
- if (
669
- ! isset( $_GET['page'] )
670
- || $_GET['page'] != 'q-export-user-data'
671
-
672
- ) {
673
-
674
- return false;
675
-
676
- }
677
-
678
- \wp_register_style( 'q-report-css', \plugins_url( 'css/q-report.css' ,__FILE__ ), '', self::version );
679
- \wp_enqueue_style( 'q-report-css' );
680
- \wp_enqueue_script( 'q_report_multi_select_js', \plugins_url( 'javascript/jquery.multi-select.js', __FILE__ ), array('jquery'), '0.9.8', false );
681
-
682
- // add script ##
683
- \wp_enqueue_script('jquery-ui-datepicker');
684
-
685
- // add style ##
686
- // \wp_enqueue_style( 'jquery-ui-datepicker' );
687
- // \wp_enqueue_style('jquery-ui-css', 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/smoothness/jquery-ui.css');
688
-
689
- }
690
-
691
-
692
-
693
-
694
- /**
695
- * Inline jQuery
696
- * @since 0.8.2
697
- */
698
- public static function jquery()
699
- {
700
-
701
- // load the scripts on only the plugin admin page
702
- if (
703
- ! isset( $_GET['page'] )
704
- || $_GET['page'] != 'q-export-user-data'
705
- ) {
706
-
707
- return false;
708
-
709
- }
710
-
711
- ?>
712
- <script>
713
-
714
- // lazy load in some jQuery validation ##
715
- jQuery(document).ready(function($) {
716
-
717
- // build super multiselect ##
718
- jQuery('#usermeta, #bp_fields, #bp_fields_update_time').multiSelect();
719
-
720
- // Select any fields from saved settings ##
721
- jQuery('#usermeta').multiSelect('select',([<?php echo( core::quote_array( self::$usermeta_saved_fields ) ); ?>]));
722
- jQuery('#bp_fields').multiSelect('select',([<?php echo( core::quote_array( self::$bp_fields_saved_fields ) ); ?>]));
723
- jQuery('#bp_fields_update_time').multiSelect('select',([<?php echo( core::quote_array( self::$bp_fields_update_time_saved_fields ) ); ?>]));
724
-
725
- // show only common ##
726
- jQuery('.usermeta-common').click(function(e){
727
- // console.log( 'Common..' );
728
- e.preventDefault();
729
- jQuery('#ms-usermeta .ms-selectable li.normal').hide();
730
- });
731
-
732
- // show all ##
733
- jQuery('.usermeta-all').click(function(e){
734
- e.preventDefault();
735
- jQuery('#ms-usermeta .ms-selectable li').show();
736
- });
737
-
738
- // select all ##
739
- jQuery('.select-all').click(function(e){
740
- e.preventDefault();
741
- jQuery( jQuery(this).parent().parent().parent().find( 'select' ) ).multiSelect( 'select_all' );
742
- });
743
-
744
- // select none ##
745
- jQuery('.select-none').click(function(e){
746
- e.preventDefault();
747
- jQuery( jQuery(this).parent().parent().parent().find( 'select' ) ).multiSelect( 'deselect_all' );
748
- });
749
-
750
-
751
- // validate number inputs ##
752
- $("input.numeric").blur(function() {
753
-
754
- //console.log("you entered "+ $(this).val());
755
-
756
- if ( $(this).val() && ! $.isNumeric( $(this).val() ) ) {
757
-
758
- //console.log("this IS NOT a number");
759
- $(this).css({ 'background': 'red', 'color': 'white' }); // highlight error ##
760
- $("p.submit .button-primary").attr('disabled','disabled'); // disable submit ##
761
-
762
- } else {
763
-
764
- $(this).css({ 'background': 'white', 'color': '#333' }); // remove error highlighting ##
765
- $("p.submit .button-primary").removeAttr('disabled'); // enable submit ##
766
-
767
- }
768
-
769
- });
770
-
771
- // toggle advanced options ##
772
- jQuery(".toggle a").click( function(e) {
773
- e.preventDefault();
774
- $toggleable = jQuery("tr.toggleable");
775
- $toggleable.toggle();
776
- if ( $toggleable.is(":visible") ) {
777
- jQuery(this).text("<?php _e( 'Hide', 'q-export-user-data' ); ?>");
778
- } else {
779
- jQuery(this).text("<?php _e( 'Show', 'q-export-user-data' ); ?>");
780
- }
781
- });
782
-
783
- // validate save button ##
784
- jQuery("#save_export").click( function(e) {
785
-
786
- // grab the value of the input ##
787
- var q_report_save_options_new_export = jQuery('#q_report_save_options_new_export').val();
788
-
789
- if ( ! q_report_save_options_new_export || q_report_save_options_new_export == '' ) {
790
-
791
- e.preventDefault(); // stop things here ##
792
- jQuery('#q_report_save_options_new_export').addClass("error");
793
-
794
- }
795
-
796
- });
797
-
798
- // remove validation on focus ##
799
- jQuery("body").on( 'focus', '#q_report_save_options_new_export', function(e) {
800
-
801
- jQuery(this).removeClass("error");
802
-
803
- });
804
-
805
- <?php
806
-
807
- // method returns an object with "first" & "last" keys ##
808
- $dates = core::get_user_registered_dates();
809
-
810
- // get date format from WP settings #
811
- $date_format = 'yy-mm-dd' ; // get_option('date_format') ? get_option('date_format') : 'yy-mm-dd' ;
812
- $start_of_week = \get_option('start_of_week') ? \get_option('start_of_week') : 'yy-mm-dd' ;
813
- #self::log( 'Date format: '.$date_format );
814
-
815
- ?>
816
-
817
- // start date picker ##
818
- jQuery('.start-datepicker').datepicker( {
819
- dateFormat : '<?php echo $date_format; ?>',
820
- minDate : '<?php echo substr( $dates["0"]->first, 0, 10 ); ?>',
821
- maxDate : '<?php echo substr( $dates["0"]->last, 0, 10 ); ?>',
822
- firstDay : '<?php echo $start_of_week; ?>'
823
- } );
824
-
825
- // end date picker ##
826
- jQuery('.end-datepicker').datepicker( {
827
- dateFormat : '<?php echo $date_format; ?>',
828
- minDate : '<?php echo substr( $dates["0"]->first, 0, 10 ); ?>',
829
- maxDate : '<?php echo substr( $dates["0"]->last, 0, 10 ); ?>',
830
- firstDay : '<?php echo $start_of_week; ?>'
831
- } );
832
-
833
- // end date picker ##
834
- // might want to set minDate to something else, but not sure
835
- // what would be best for everyone
836
- jQuery('.updated-datepicker').datepicker( {
837
- dateFormat : '<?php echo $date_format; ?>',
838
- minDate : '<?php echo substr( $dates["0"]->first, 0, 10 ); ?>',
839
- maxDate : '0',
840
- firstDay : '<?php echo $start_of_week; ?>'
841
- } );
842
-
843
- });
844
-
845
- </script>
846
- <?php
847
-
848
- }
849
-
850
-
851
-
852
-
853
- /**
854
- * Inline CSS
855
- *
856
- * @since 0.8.2
857
- */
858
- public static function css()
859
- {
860
-
861
- // load the scripts on only the plugin admin page
862
- if (
863
- ! isset( $_GET['page'] )
864
- || $_GET['page'] != 'q-export-user-data'
865
- ) {
866
-
867
- return false;
868
-
869
- }
870
-
871
- ?>
872
- <style>
873
- .toggleable { display: none; }
874
- .hidden { display: none; }
875
- </style>
876
- <?php
877
-
878
- }
879
-
880
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace q\eud\admin;
4
+
5
+ use q\eud\core\core as core;
6
+ use q\eud\core\helper as helper;
7
+ use q\eud\core\user as user;
8
+ use q\eud\core\buddypress as buddypress;
9
+ use q\eud\api\admin as api_admin;
10
+
11
+ // load it up ##
12
+ \q\eud\admin\admin::run();
13
+
14
+ class admin extends \q_export_user_data {
15
+
16
+ public static function run()
17
+ {
18
+
19
+ #global $pagenow;
20
+
21
+ if ( \is_admin() ) {
22
+
23
+ // add export menu inside admin ##
24
+ \add_action( 'admin_menu', array( get_class(), 'add_menu' ) );
25
+
26
+ // UI style and functionality ##
27
+ \add_action( 'admin_enqueue_scripts', array( get_class(), 'admin_enqueue_scripts' ), 1 );
28
+ \add_action( 'admin_footer', array( get_class(), 'jquery' ), 100000 );
29
+ \add_action( 'admin_footer', array( get_class(), 'css' ), 100000 );
30
+
31
+ }
32
+
33
+ }
34
+
35
+
36
+
37
+ /**
38
+ * Add administration menus
39
+ *
40
+ * @since 0.1
41
+ **/
42
+ public static function add_menu()
43
+ {
44
+
45
+ add_users_page (
46
+ __( 'Export User Data', 'q-export-user-data' ),
47
+ __( 'Export User Data', 'q-export-user-data' ),
48
+ \apply_filters( 'q/eud/admin_capability', 'list_users' ),
49
+ 'q-export-user-data',
50
+ array(
51
+ get_class(),
52
+ 'admin_page'
53
+ )
54
+ );
55
+
56
+ }
57
+
58
+
59
+ /**
60
+ * Content of the admin page
61
+ *
62
+ * @since 0.1
63
+ */
64
+ public static function admin_page()
65
+ {
66
+
67
+ // quick security check ##
68
+ if ( ! \current_user_can( \apply_filters( 'q/eud/admin_capability', 'list_users' ) ) ) {
69
+
70
+ \wp_die( __( 'You do not have sufficient permissions to access this page.', 'q-export-user-data' ) );
71
+
72
+ }
73
+
74
+ // Save settings button was pressed ##
75
+ if (
76
+ isset( $_POST['save_export'] )
77
+ && \check_admin_referer( 'q-eud-admin-page', '_wpnonce-q-eud-admin-page' )
78
+ ) {
79
+
80
+ // start with an empty variable ##
81
+ $save_export = "";
82
+
83
+ if ( ! empty( $_POST['save_new_export_name'] ) ) {
84
+
85
+ // assign value ##
86
+ $save_export = $_POST['save_new_export_name'];
87
+
88
+ } elseif ( ! empty( $_POST['export_name'] ) ) {
89
+
90
+ $save_export = $_POST['export_name'];
91
+
92
+ }
93
+
94
+ // clean up $save_export ##
95
+ $save_export = \sanitize_text_field( $save_export );
96
+
97
+ // Build array of $options to save and save them ##
98
+ if ( isset( $save_export ) ) {
99
+
100
+ // prepare all array values ##
101
+ $usermeta =
102
+ isset( $_POST['usermeta'] ) ?
103
+ array_map( 'sanitize_text_field',
104
+ $_POST['usermeta'] ) :
105
+ '';
106
+ $bp_fields =
107
+ isset( $_POST['bp_fields'] ) ?
108
+ array_map( 'sanitize_text_field', $_POST['bp_fields'] ) :
109
+ '' ;
110
+ $bp_fields_update =
111
+ isset( $_POST['bp_fields_update_time'] ) ?
112
+ array_map( 'sanitize_text_field', $_POST['bp_fields_update_time'] ) :
113
+ '' ;
114
+ $format =
115
+ isset( $_POST['format'] ) ?
116
+ \sanitize_text_field( $_POST['format'] ) :
117
+ '' ;
118
+ $role =
119
+ isset( $_POST['role'] ) ?
120
+ \sanitize_text_field( $_POST['role'] ) :
121
+ '' ;
122
+ $roles =
123
+ isset( $_POST['roles'] ) ?
124
+ \sanitize_text_field( $_POST['roles'] ) :
125
+ '' ;
126
+ $user_fields =
127
+ isset( $_POST['user_fields'] ) ?
128
+ array_map( 'sanitize_text_field', $_POST['user_fields'] ) :
129
+ '0' ;
130
+ $groups =
131
+ isset( $_POST['groups'] ) ?
132
+ \sanitize_text_field( $_POST['groups'] ) :
133
+ '0' ;
134
+ $start_date =
135
+ isset( $_POST['start_date'] ) ?
136
+ \sanitize_text_field( $_POST['start_date'] ) :
137
+ '' ;
138
+ $end_date =
139
+ isset( $_POST['end_date'] ) ?
140
+ \sanitize_text_field( $_POST['end_date'] ) :
141
+ '' ;
142
+ $limit_offset =
143
+ isset( $_POST['limit_offset'] ) ?
144
+ \sanitize_text_field( $_POST['limit_offset'] ) :
145
+ '' ;
146
+ $limit_total =
147
+ isset( $_POST['limit_total'] ) ?
148
+ \sanitize_text_field( $_POST['limit_total'] ) :
149
+ '' ;
150
+ $updated_since_date =
151
+ isset( $_POST['updated_since_date'] ) ?
152
+ \sanitize_text_field( $_POST['updated_since_date'] ) :
153
+ '' ;
154
+ $field_updated_since =
155
+ isset( $_POST['bp_field_updated_since'] ) ?
156
+ array_map( 'sanitize_text_field', $_POST['bp_field_updated_since'] ) :
157
+ '';
158
+
159
+ // assign all values to an array ##
160
+ $save_array = array (
161
+ 'usermeta_saved_fields' => $usermeta,
162
+ 'bp_fields_saved_fields' => $bp_fields,
163
+ 'bp_fields_update_time_saved_fields' => $bp_fields_update,
164
+ 'role' => $role,
165
+ 'roles' => $roles,
166
+ 'user_fields' => $user_fields,
167
+ 'groups' => $groups,
168
+ 'start_date' => $start_date,
169
+ 'end_date' => $end_date,
170
+ 'limit_offset' => $limit_offset,
171
+ 'limit_total' => $limit_total,
172
+ 'updated_since_date' => $updated_since_date,
173
+ 'field_updated_since' => $field_updated_since,
174
+ 'format' => $format
175
+ );
176
+
177
+ // store the options, for next load ##
178
+ user::set_user_options( $save_export, $save_array );
179
+
180
+ // Display the settings the user just saved instead of blanking the form ##
181
+ $_POST['load_export'] = 'Load Settings';
182
+ $_POST['export_name'] = $save_export;
183
+
184
+ }
185
+
186
+ }
187
+
188
+ // Load settings button was pressed ( or option saved and $_POST variables hijacked )##
189
+ if (
190
+ isset( $_POST['load_export'] )
191
+ && isset( $_POST['export_name'] )
192
+ && \check_admin_referer( 'q-eud-admin-page', '_wpnonce-q-eud-admin-page' )
193
+ ) {
194
+
195
+ user::get_user_options_by_export( \sanitize_text_field( $_POST['export_name'] ) );
196
+
197
+ }
198
+
199
+ // Delete settings button was pressed ##
200
+ if (
201
+ isset( $_POST['delete_export'] )
202
+ && isset( $_POST['export_name'] )
203
+ && \check_admin_referer( 'q-eud-admin-page', '_wpnonce-q-eud-admin-page' )
204
+ ) {
205
+
206
+ user::delete_user_options( \sanitize_text_field( $_POST['export_name'] ) );
207
+
208
+ }
209
+
210
+ ?>
211
+ <div class="wrap">
212
+ <h2><?php \_e( 'Export User Data', 'q-export-user-data' ); ?></h2>
213
+ <?php
214
+
215
+ // nothing happening? ##
216
+ if ( isset( $_GET['error'] ) ) {
217
+ echo '<div class="updated"><p><strong>' . \__( 'No users found.', 'q-export-user-data' ) . '</strong></p></div>';
218
+ }
219
+
220
+ ?>
221
+ <form method="post" action="" enctype="multipart/form-data">
222
+ <?php \wp_nonce_field( 'q-eud-admin-page', '_wpnonce-q-eud-admin-page' ); ?>
223
+ <table class="form-table">
224
+ <?php
225
+
226
+ // allow admin to select user meta fields to export ##
227
+ global $wpdb;
228
+
229
+ // filterable SQL ##
230
+ $meta_keys = \apply_filters(
231
+ 'q/eud/admin/sql',
232
+ $wpdb->get_results( "SELECT distinct(meta_key) FROM $wpdb->usermeta" )
233
+ );
234
+
235
+ // filterable sort ##
236
+ \apply_filters(
237
+ 'q/eud/admin/sort',
238
+ asort( $meta_keys )
239
+ );
240
+
241
+ // get meta_key value from object ##
242
+ $meta_keys = \wp_list_pluck( $meta_keys, 'meta_key' );
243
+
244
+ // allow array to be filtered ##
245
+ $meta_keys_common = \apply_filters( 'q/eud/admin/meta_keys_common', [] );
246
+
247
+ // test array ##
248
+ #helper::log( $meta_keys );
249
+ #helper::log( $meta_keys_common );
250
+
251
+ // check if we got anything ? ##
252
+ if ( $meta_keys ) {
253
+
254
+ ?>
255
+ <tr valign="top">
256
+ <th scope="row">
257
+ <label for="q_eud_usermeta"><?php \_e( 'User Meta Fields', 'q-export-user-data' ); ?></label>
258
+ <p class="filter" style="margin: 10px 0 0;">
259
+ <?php \_e('Filter', 'q-export-user-data'); ?>: <a href="#" class="usermeta-all"><?php \_e('All', 'q-export-user-data'); ?></a> | <a href="#" class="usermeta-common"><?php \_e('Common', 'q-export-user-data'); ?></a>
260
+ </p>
261
+ <p class="filter" style="margin: 10px 0 0;">
262
+ <?php \_e('Select', 'q-export-user-data'); ?>: <a href="#" class="select-all"><?php \_e('All', 'q-export-user-data'); ?></a> | <a href="#" class="select-none"><?php \_e('None', 'q-export-user-data'); ?></a>
263
+ </p>
264
+ </th>
265
+ <td>
266
+ <select multiple="multiple" id="usermeta" name="usermeta[]">
267
+ <?php
268
+
269
+ foreach ( $meta_keys as $key ) {
270
+
271
+ // filter key displayed ##
272
+ $display_key = \apply_filters( 'q/eud/admin/display_key', $key );
273
+
274
+ // class ##
275
+ $usermeta_class = 'normal';
276
+
277
+ foreach ( $meta_keys_common as $drop ) {
278
+
279
+ #helper::log( 'Checking: '.$drop );
280
+
281
+ if ( strpos( $key, $drop ) !== false ) {
282
+
283
+ #helper::log( 'Checking: '.$key );
284
+
285
+ // https://wordpress.org/support/topic/bugfix-numbers-in-export-headers?replies=1
286
+ // removed $key = assignment, as not required ##
287
+ if ( ( array_search( $key, $meta_keys ) ) !== false ) {
288
+
289
+ #helper::log( 'Found: '.$key );
290
+
291
+ $usermeta_class = 'common';
292
+
293
+ }
294
+
295
+ }
296
+
297
+ }
298
+
299
+ // print key ##
300
+ echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."' class='".$usermeta_class."'>$display_key</option>";
301
+
302
+ }
303
+ ?>
304
+ </select>
305
+ <p class="description"><?php
306
+ printf(
307
+ \__( 'Select the user meta keys to export, use the filters to simplify the list.', 'q-export-user-data' )
308
+ );
309
+ ?></p>
310
+ </td>
311
+ </tr>
312
+ <?php
313
+
314
+ } // meta_keys found ##
315
+
316
+ ?>
317
+ <?php
318
+
319
+ // buddypress x profile data ##
320
+ if ( $bp_fields = buddypress::get_fields() ) {
321
+
322
+ ?>
323
+ <tr valign="top">
324
+ <th scope="row">
325
+ <label for="q_eud_xprofile"><?php \_e( 'BP xProfile Fields', 'q-export-user-data' ); ?></label>
326
+ <p class="filter" style="margin: 10px 0 0;">
327
+ <?php \_e('Select', 'q-export-user-data'); ?>: <a href="#" class="select-all"><?php \_e('All', 'q-export-user-data'); ?></a> | <a href="#" class="select-none"><?php \_e('None', 'q-export-user-data'); ?></a>
328
+ </p>
329
+ </th>
330
+ <td>
331
+ <select multiple="multiple" id="bp_fields" name="bp_fields[]">
332
+ <?php
333
+
334
+ foreach ( $bp_fields as $key ) {
335
+
336
+ // print key ##
337
+ echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."'>$key</option>";
338
+
339
+ }
340
+
341
+ ?>
342
+ </select>
343
+ <p class="description"><?php
344
+ printf(
345
+ \__( 'Select the BuddyPress XProfile keys to export', 'q-export-user-data' )
346
+ );
347
+ ?></p>
348
+ </td>
349
+ </tr>
350
+ <?php
351
+
352
+ // allow export of update times ##
353
+
354
+ ?>
355
+ <tr valign="top" class="toggleable">
356
+ <th scope="row">
357
+ <label for="q_eud_xprofile"><?php \_e( 'BP xProfile Fields Update Time', 'q-export-user-data' ); ?></label>
358
+ <p class="filter" style="margin: 10px 0 0;">
359
+ <?php \_e('Select', 'q-export-user-data'); ?>: <a href="#" class="select-all"><?php \_e('All', 'q-export-user-data'); ?></a> | <a href="#" class="select-none"><?php _e('None', 'q-export-user-data'); ?></a>
360
+ </p>
361
+ </th>
362
+ <td>
363
+ <select multiple="multiple" id="bp_fields_update_time" name="bp_fields_update_time[]">
364
+ <?php
365
+
366
+ foreach ( $bp_fields as $key ) {
367
+
368
+ echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."'>$key</option>";
369
+
370
+ }
371
+
372
+ ?>
373
+ </select>
374
+ <p class="description"><?php
375
+ printf(
376
+ \__( 'Select the BuddyPress XProfile keys updated dates to export', 'q-export-user-data' )
377
+ );
378
+ ?></p>
379
+ </td>
380
+ </tr>
381
+
382
+ <tr valign="top" class="toggleable">
383
+ <th scope="row"><label for="groups"><?php \_e( 'BP User Groups', 'q-export-user-data' ); ?></label></th>
384
+ <td>
385
+ <input id='groups' type='checkbox' name='groups' value='1' <?php \checked( isset ( self::$groups ) ? intval ( self::$groups ) : '', 1 ); ?> />
386
+ <p class="description"><?php
387
+ printf(
388
+ \__( 'Include BuddyPress Group Data. <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
389
+ , \esc_html('https://codex.buddypress.org/buddypress-components-and-features/groups/')
390
+ , 'Codex'
391
+ );
392
+ ?></p>
393
+ </td>
394
+ </tr>
395
+ <?php
396
+
397
+ } // BP installed and active ##
398
+
399
+ ?>
400
+ <tr valign="top" class="toggleable">
401
+ <th scope="row"><label for="user_fields"><?php \_e( 'Standard User Fields', 'q-export-user-data' ); ?></label></th>
402
+ <td>
403
+ <input id='user_fields' type='checkbox' name='user_fields' value='1' <?php \checked( isset ( self::$user_fields ) ? intval ( self::$user_fields ) : '', 1 ); ?> />
404
+ <p class="description"><?php
405
+
406
+ #self::log( 'user_fields: '.self::$user_fields );
407
+ #echo 'user_fields: '. self::$user_fields;
408
+
409
+ printf(
410
+ \__( 'Include Standard user profile fields, such as user_login. <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
411
+ , \esc_html('https://codex.wordpress.org/Database_Description#Table:_wp_users')
412
+ , 'Codex'
413
+ );
414
+
415
+ ?></p>
416
+ </td>
417
+ </tr>
418
+
419
+ <tr valign="top" class="toggleable">
420
+ <th scope="row"><label for="q_eud_users_role"><?php \_e( 'Role', 'q-export-user-data' ); ?></label></th>
421
+ <td>
422
+ <select name="role" id="q_eud_users_role">
423
+ <?php
424
+
425
+ echo '<option value="">' . \__( 'All Roles', 'q-export-user-data' ) . '</option>';
426
+
427
+ global $wp_roles;
428
+
429
+ foreach ( $wp_roles->role_names as $role => $name ) {
430
+
431
+ if ( isset ( self::$role ) && ( self::$role == $role ) ) {
432
+
433
+ echo "\n\t<option selected value='" . \esc_attr( $role ) . "'>$name</option>";
434
+
435
+ } else {
436
+
437
+ echo "\n\t<option value='" . \esc_attr( $role ) . "'>$name</option>";
438
+
439
+ }
440
+ }
441
+
442
+
443
+ ?>
444
+ </select>
445
+ <p class="description"><?php
446
+ printf(
447
+ \__( 'Filter the exported users by a WordPress Role. <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
448
+ , \esc_html('http://codex.wordpress.org/Roles_and_Capabilities')
449
+ , 'Codex'
450
+ );
451
+ ?></p>
452
+ </td>
453
+ </tr>
454
+
455
+ <tr valign="top" class="toggleable">
456
+ <th scope="row"><label for="roles"><?php \_e( 'User Roles', 'q-export-user-data' ); ?></label></th>
457
+ <td>
458
+ <input id='roles' type='checkbox' name='roles' value='1' <?php \checked( isset ( self::$roles ) ? intval ( self::$roles ) : '', 1 ); ?> />
459
+ <p class="description"><?php
460
+ printf(
461
+ \__( 'Include all of the users <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
462
+ , \esc_html('http://codex.wordpress.org/Roles_and_Capabilities')
463
+ , 'Roles'
464
+ );
465
+ ?></p>
466
+ </td>
467
+ </tr>
468
+
469
+ <tr valign="top" class="toggleable">
470
+ <th scope="row"><label><?php \_e( 'Registered', 'q-export-user-data' ); ?></label></th>
471
+ <td>
472
+ <input type="text" id="q_eud_users_start_date" name="start_date" value="<?php echo self::$start_date; ?>" class="start-datepicker" />
473
+ <input type="text" id="q_eud_users_end_date" name="end_date" value="<?php echo self::$end_date; ?>" class="end-datepicker" />
474
+ <p class="description"><?php
475
+ printf(
476
+ \__( 'Pick a start and end user registration date to limit the results.', 'q-export-user-data' )
477
+ );
478
+ ?></p>
479
+ </td>
480
+ </tr>
481
+
482
+ <tr valign="top" class="toggleable">
483
+ <th scope="row"><label><?php \_e( 'Limit Range', 'q-export-user-data' ); ?></label></th>
484
+ <td>
485
+ <input name="limit_offset" type="text" id="q_eud_users_limit_offset" value="<?php echo( self::$limit_offset ); ?>" class="regular-text code numeric" style="width: 136px;" placeholder="<?php _e( 'Offset', 'q-export-user-data' ); ?>">
486
+ <input name="limit_total" type="text" id="q_eud_users_limit_total" value="<?php echo ( self::$limit_total ); ?>" class="regular-text code numeric" style="width: 136px;" placeholder="<?php _e( 'Total', 'q-export-user-data' ); ?>">
487
+ <p class="description"><?php
488
+ printf(
489
+ \__( 'Enter an offset start number and a total number of users to export. <a href="%s" target="_blank">%s</a>', 'q-export-user-data' )
490
+ , \esc_html('http://codex.wordpress.org/Function_Reference/get_users#Parameters')
491
+ , 'Codex'
492
+ );
493
+ ?></p>
494
+ </td>
495
+ </tr>
496
+ <?php
497
+
498
+ // buddypress x profile data ##
499
+ if ( $bp_fields = buddypress::get_fields() ) {
500
+
501
+ ?>
502
+ <tr valign="top" class="toggleable">
503
+ <th scope="row"><label><?php \_e( 'Updated Since', 'q-export-user-data' ); ?></label></th>
504
+ <td>
505
+ <input type="text" id="q_eud_updated_since_date" name="updated_since_date" value="<?php echo self::$updated_since_date; ?>" class="updated-datepicker" />
506
+ <select id="bp_field_updated_since" name="bp_field_updated_since">
507
+ <?php
508
+
509
+ foreach ( $bp_fields as $key ) {
510
+
511
+ if ( self::$field_updated_since == $key ) {
512
+
513
+ echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."' selected>$key</option>";
514
+
515
+ } else {
516
+
517
+ echo "<option value='".\esc_attr( $key )."' title='".\esc_attr( $key )."'>$key</option>";
518
+
519
+ }
520
+
521
+ }
522
+
523
+ ?>
524
+ </select>
525
+
526
+ <p class="description"><?php
527
+ printf(
528
+ \__( 'Limit the results to users who have updated this extended profile field after this date.', 'q-export-user-data' )
529
+ );
530
+ ?></p>
531
+ </td>
532
+ </tr>
533
+ <?php
534
+
535
+ } // bp date ##
536
+
537
+ // pull in extra export options from api ##
538
+ if ( $api_fields = \apply_filters( 'q/eud/api/admin/fields', [] ) ) {
539
+
540
+ foreach( $api_fields as $field ) {
541
+
542
+ api_admin::render( $field );
543
+
544
+ }
545
+
546
+ }
547
+
548
+ ?>
549
+ <tr valign="top">
550
+ <th scope="row"><label for="q_eud_users_format"><?php \_e( 'Format', 'q-export-user-data' ); ?></label></th>
551
+ <td>
552
+ <select name="format" id="q_eud_users_format">
553
+ <?php
554
+ /*
555
+ if ( isset ( self::$format ) && ( self::$format == 'excel2003' ) ) {
556
+
557
+ echo '<option selected value="excel2003">' . __( 'Excel 2003 (xls)', 'q-export-user-data' ) . '</option>';
558
+
559
+ } else {
560
+
561
+ echo '<option value="excel2003">' . __( 'Excel 2003 (xls)', 'q-export-user-data' ) . '</option>';
562
+
563
+ }
564
+ */
565
+
566
+ if ( isset ( self::$format ) && ( self::$format == 'excel2007' ) ) {
567
+
568
+ echo '<option selected value="excel2007">' . __( 'Excel 2007 (xlsx)', 'q-export-user-data' ) . '</option>';
569
+
570
+ } else {
571
+
572
+ echo '<option value="excel2007">' . __( 'Excel 2007 (xlsx)', 'q-export-user-data' ) . '</option>';
573
+
574
+ }
575
+
576
+ if ( isset ( self::$format ) && ( self::$format == 'csv' ) ) {
577
+
578
+ echo '<option selected value="csv">' . __( 'CSV', 'q-export-user-data' ) . '</option>';
579
+
580
+ } else {
581
+
582
+ echo '<option value="csv">' . __( 'CSV', 'q-export-user-data' ) . '</option>';
583
+
584
+ }
585
+ ?>
586
+ </select>
587
+ <p class="description"><?php
588
+ printf(
589
+ \__( 'Select the format for the export file.', 'q-export-user-data' )
590
+ );
591
+ ?></p>
592
+ </td>
593
+ </tr>
594
+
595
+ <tr valign="top" class="remember">
596
+ <th scope="row"><label for="q_eud_save_options"><?php \_e( 'Stored Options', 'q-export-user-data' ); ?></label></th>
597
+ <td>
598
+
599
+ <div class="row">
600
+ <input type="text" class="regular-text" name="save_new_export_name" id="q_eud_save_options_new_export" placeholder="<?php \_e( 'Export Name', 'q-export-user-data' ); ?>" value="<?php echo isset( $_POST['export_name'] ) ? \sanitize_text_field( $_POST['export_name'] ) : '' ; ?>">
601
+ <input type="submit" id="save_export" class="button-primary" name="save_export" value="<?php \_e( 'Save', 'q-export-user-data' ); ?>" />
602
+ </div>
603
+ <?php
604
+
605
+ // check if the user has any saved exports ##
606
+ if ( user::get_user_options() ) {
607
+
608
+ ?>
609
+ <div class="row">
610
+ <select name="export_name" id="q_eud_save_options" class="regular-text">
611
+ <?php
612
+
613
+ // loop over each saved export ##
614
+ foreach( user::get_user_options() as $export ) {
615
+
616
+ // select Loaded export name, if selected ##
617
+ if (
618
+ isset( $_POST['load_export'] )
619
+ && isset( $_POST['export_name'] )
620
+ && ( \sanitize_text_field( $_POST['export_name'] ) == $export )
621
+ ) {
622
+
623
+ echo "<option selected value='$export'>".$export."</option>";
624
+
625
+ // just list previous export name ##
626
+ } else {
627
+
628
+ echo "<option value='$export'>".$export."</option>";
629
+
630
+ }
631
+
632
+ }
633
+
634
+ ?>
635
+ </select>
636
+
637
+ <input type="submit" id="load_export" class="button-primary" name="load_export" value="<?php _e( 'Load', 'q-export-user-data' ); ?>" />
638
+ <input type="submit" id="delete_export" class="button-primary" name="delete_export" value="<?php _e( 'Delete', 'q-export-user-data' ); ?>" />
639
+ <?php
640
+
641
+ }
642
+
643
+ ?>
644
+ </div>
645
+ <p class="description"><?php \_e( 'Save, load or delete your stored export options.', 'q-export-user-data' ); ?></p>
646
+
647
+ </td>
648
+ </tr>
649
+
650
+ <tr valign="top">
651
+ <th scope="row">
652
+ <label for="q_eud_xprofile"><?php \_e( 'Advanced Options', 'q-export-user-data' ); ?></label>
653
+ </th>
654
+ <td>
655
+ <div class="toggle">
656
+ <a href="#"><?php \_e( 'Show', 'q-export-user-data' ); ?></a>
657
+ </div>
658
+ </td>
659
+ </tr>
660
+
661
+ </table>
662
+ <p class="submit">
663
+ <input type="hidden" name="_wp_http_referer" value="<?php echo \esc_url( $_SERVER['REQUEST_URI'] ); ?>" />
664
+ <input type="submit" class="button-primary" value="<?php \_e( 'Run Export', 'q-export-user-data' ); ?>" />
665
+ </p>
666
+ </form>
667
+ </div>
668
+
669
+ <?php
670
+ }
671
+
672
+
673
+
674
+ /**
675
+ * style and interaction
676
+ */
677
+ public static function admin_enqueue_scripts( $hook )
678
+ {
679
+
680
+ // load the scripts on only the plugin admin page ##
681
+ if (
682
+ ! isset( $_GET['page'] )
683
+ || $_GET['page'] != 'q-export-user-data'
684
+
685
+ ) {
686
+
687
+ return false;
688
+
689
+ }
690
+
691
+ \wp_register_style( 'q-eud-css', \plugins_url( 'css/q-eud.css' ,__FILE__ ), '', self::version );
692
+ \wp_enqueue_style( 'q-eud-css' );
693
+ \wp_enqueue_script( 'q_eud_multi_select_js', \plugins_url( 'javascript/jquery.multi-select.js', __FILE__ ), array('jquery'), '0.9.8', false );
694
+
695
+ // add script ##
696
+ \wp_enqueue_script('jquery-ui-datepicker');
697
+ \wp_register_style('jquery-ui', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css');
698
+ \wp_enqueue_style('jquery-ui');
699
+
700
+ // add style ##
701
+ // \wp_enqueue_style( 'jquery-ui-datepicker' );
702
+ // \wp_enqueue_style('jquery-ui-css', 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/smoothness/jquery-ui.css');
703
+
704
+ }
705
+
706
+
707
+
708
+
709
+ /**
710
+ * Inline jQuery
711
+ * @since 0.8.2
712
+ */
713
+ public static function jquery()
714
+ {
715
+
716
+ // load the scripts on only the plugin admin page
717
+ if (
718
+ ! isset( $_GET['page'] )
719
+ || $_GET['page'] != 'q-export-user-data'
720
+ ) {
721
+
722
+ return false;
723
+
724
+ }
725
+
726
+ ?>
727
+ <script>
728
+
729
+ // lazy load in some jQuery validation ##
730
+ jQuery(document).ready(function($) {
731
+
732
+ // build super multiselect ##
733
+ jQuery('#usermeta, #bp_fields, #bp_fields_update_time').multiSelect();
734
+
735
+ // Select any fields from saved settings ##
736
+ jQuery('#usermeta').multiSelect('select',([<?php echo( core::quote_array( self::$usermeta_saved_fields ) ); ?>]));
737
+ jQuery('#bp_fields').multiSelect('select',([<?php echo( core::quote_array( self::$bp_fields_saved_fields ) ); ?>]));
738
+ jQuery('#bp_fields_update_time').multiSelect('select',([<?php echo( core::quote_array( self::$bp_fields_update_time_saved_fields ) ); ?>]));
739
+
740
+ // show only common ##
741
+ jQuery('.usermeta-common').click(function(e){
742
+ // console.log( 'Common..' );
743
+ e.preventDefault();
744
+ jQuery('#ms-usermeta .ms-selectable li.normal').hide();
745
+ });
746
+
747
+ // show all ##
748
+ jQuery('.usermeta-all').click(function(e){
749
+ e.preventDefault();
750
+ jQuery('#ms-usermeta .ms-selectable li').show();
751
+ });
752
+
753
+ // select all ##
754
+ jQuery('.select-all').click(function(e){
755
+ e.preventDefault();
756
+ jQuery( jQuery(this).parent().parent().parent().find( 'select' ) ).multiSelect( 'select_all' );
757
+ });
758
+
759
+ // select none ##
760
+ jQuery('.select-none').click(function(e){
761
+ e.preventDefault();
762
+ jQuery( jQuery(this).parent().parent().parent().find( 'select' ) ).multiSelect( 'deselect_all' );
763
+ });
764
+
765
+
766
+ // validate number inputs ##
767
+ $("input.numeric").blur(function() {
768
+
769
+ //console.log("you entered "+ $(this).val());
770
+
771
+ if ( $(this).val() && ! $.isNumeric( $(this).val() ) ) {
772
+
773
+ //console.log("this IS NOT a number");
774
+ $(this).css({ 'background': 'red', 'color': 'white' }); // highlight error ##
775
+ $("p.submit .button-primary").attr('disabled','disabled'); // disable submit ##
776
+
777
+ } else {
778
+
779
+ $(this).css({ 'background': 'white', 'color': '#333' }); // remove error highlighting ##
780
+ $("p.submit .button-primary").removeAttr('disabled'); // enable submit ##
781
+
782
+ }
783
+
784
+ });
785
+
786
+ // toggle advanced options ##
787
+ jQuery(".toggle a").click( function(e) {
788
+ e.preventDefault();
789
+ $toggleable = jQuery("tr.toggleable");
790
+ $toggleable.toggle();
791
+ if ( $toggleable.is(":visible") ) {
792
+ jQuery(this).text("<?php _e( 'Hide', 'q-export-user-data' ); ?>");
793
+ } else {
794
+ jQuery(this).text("<?php _e( 'Show', 'q-export-user-data' ); ?>");
795
+ }
796
+ });
797
+
798
+ // validate save button ##
799
+ jQuery("#save_export").click( function(e) {
800
+
801
+ // grab the value of the input ##
802
+ var q_eud_save_options_new_export = jQuery('#q_eud_save_options_new_export').val();
803
+
804
+ if ( ! q_eud_save_options_new_export || q_eud_save_options_new_export == '' ) {
805
+
806
+ e.preventDefault(); // stop things here ##
807
+ jQuery('#q_eud_save_options_new_export').addClass("error");
808
+
809
+ }
810
+
811
+ });
812
+
813
+ // remove validation on focus ##
814
+ jQuery("body").on( 'focus', '#q_eud_save_options_new_export', function(e) {
815
+
816
+ jQuery(this).removeClass("error");
817
+
818
+ });
819
+
820
+ <?php
821
+
822
+ // method returns an object with "first" & "last" keys ##
823
+ $dates = core::get_user_registered_dates();
824
+
825
+ // get date format from WP settings #
826
+ $date_format = 'yy-mm-dd' ; // get_option('date_format') ? get_option('date_format') : 'yy-mm-dd' ;
827
+ $start_of_week = \get_option('start_of_week') ? \get_option('start_of_week') : 'yy-mm-dd' ;
828
+ #self::log( 'Date format: '.$date_format );
829
+
830
+ ?>
831
+
832
+ // start date picker ##
833
+ jQuery('.start-datepicker').datepicker( {
834
+ dateFormat : '<?php echo $date_format; ?>',
835
+ minDate : '<?php echo substr( $dates["0"]->first, 0, 10 ); ?>',
836
+ maxDate : '<?php echo substr( $dates["0"]->last, 0, 10 ); ?>',
837
+ firstDay : '<?php echo $start_of_week; ?>'
838
+ } );
839
+
840
+ // end date picker ##
841
+ jQuery('.end-datepicker').datepicker( {
842
+ dateFormat : '<?php echo $date_format; ?>',
843
+ minDate : '<?php echo substr( $dates["0"]->first, 0, 10 ); ?>',
844
+ maxDate : '<?php echo substr( $dates["0"]->last, 0, 10 ); ?>',
845
+ firstDay : '<?php echo $start_of_week; ?>'
846
+ } );
847
+
848
+ // end date picker ##
849
+ // might want to set minDate to something else, but not sure
850
+ // what would be best for everyone
851
+ jQuery('.updated-datepicker').datepicker( {
852
+ dateFormat : '<?php echo $date_format; ?>',
853
+ minDate : '<?php echo substr( $dates["0"]->first, 0, 10 ); ?>',
854
+ maxDate : '0',
855
+ firstDay : '<?php echo $start_of_week; ?>'
856
+ } );
857
+
858
+ });
859
+
860
+ </script>
861
+ <?php
862
+
863
+ }
864
+
865
+
866
+
867
+
868
+ /**
869
+ * Inline CSS
870
+ *
871
+ * @since 0.8.2
872
+ */
873
+ public static function css()
874
+ {
875
+
876
+ // load the scripts on only the plugin admin page
877
+ if (
878
+ ! isset( $_GET['page'] )
879
+ || $_GET['page'] != 'q-export-user-data'
880
+ ) {
881
+
882
+ return false;
883
+
884
+ }
885
+
886
+ ?>
887
+ <style>
888
+ .toggleable { display: none; }
889
+ .hidden { display: none; }
890
+ </style>
891
+ <?php
892
+
893
+ }
894
+
895
+ }
library/admin/css/{q-report.css → q-eud.css} RENAMED
@@ -1,134 +1,134 @@
1
- /*
2
- export-user-data.css
3
-
4
- @since 0.9.6
5
- */
6
-
7
-
8
- /* general layout */
9
-
10
- .form-table tr.remember div.row:first-child {
11
- margin-bottom: 10px;
12
- }
13
-
14
- .form-table tr.remember input.button-primary {
15
- margin-left: 5px;
16
- }
17
-
18
- .form-table tr.remember select {
19
- width: 25em;
20
- }
21
-
22
- input.error {
23
- background: #D54E21;
24
- color: #fff;
25
- border: 1px solid #CCC;
26
- }
27
-
28
- th p.filter {
29
- width: 100%;
30
- }
31
-
32
- /* form inputs */
33
-
34
-
35
- /* multiselects */
36
-
37
- .ms-container{
38
- background: transparent url('image/switch.png') no-repeat 50% 50%;
39
- /* width: 600px; */
40
- }
41
-
42
- .ms-container:after{
43
- content: ".";
44
- display: block;
45
- height: 0;
46
- line-height: 0;
47
- font-size: 0;
48
- clear: both;
49
- min-height: 0;
50
- visibility: hidden;
51
- }
52
-
53
- .ms-container .ms-selectable, .ms-container .ms-selection{
54
- background: #fff;
55
- color: #555555;
56
- float: left;
57
- width: 45%;
58
- }
59
-
60
- .ms-container .ms-list{
61
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
62
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
63
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
64
- -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
65
- -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
66
- -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
67
- -o-transition: border linear 0.2s, box-shadow linear 0.2s;
68
- transition: border linear 0.2s, box-shadow linear 0.2s;
69
- border: 1px solid #ccc;
70
- -webkit-border-radius: 3px;
71
- -moz-border-radius: 3px;
72
- border-radius: 3px;
73
- position: relative;
74
- height: 134px;
75
- padding: 0;
76
- overflow-y: auto;
77
- overflow-x: hidden;
78
- }
79
-
80
- .ms-container .ms-selectable{
81
- margin-right: 10%;
82
- }
83
-
84
- .ms-container .ms-list.ms-focus{
85
- border-color: rgba(82, 168, 236, 0.8);
86
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
87
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
88
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
89
- outline: 0;
90
- outline: thin dotted \9;
91
- }
92
-
93
- .ms-container ul{
94
- margin: 0;
95
- list-style-type: none;
96
- padding: 0;
97
- }
98
-
99
- .ms-container .ms-optgroup-container{
100
- width: 100%;
101
- }
102
-
103
- .ms-container .ms-optgroup-label{
104
- margin: 0;
105
- padding: 5px 0px 0px 5px;
106
- cursor: pointer;
107
- color: #999;
108
- }
109
-
110
- .ms-container .ms-selectable li.ms-elem-selectable,
111
- .ms-container .ms-selection li.ms-elem-selection{
112
- border-bottom: 1px #eee solid;
113
- padding: 4px 10px;
114
- color: #555;
115
- font-size: 14px;
116
- margin-bottom: 0px;
117
- }
118
-
119
- .ms-container .ms-selectable li.ms-hover,
120
- .ms-container .ms-selection li.ms-hover{
121
- cursor: pointer;
122
- color: #fff;
123
- text-decoration: none;
124
- background-color: #08c;
125
- margin-bottom: 0px;
126
- }
127
-
128
- .ms-container .ms-selectable li.disabled,
129
- .ms-container .ms-selection li.disabled{
130
- background-color: #eee;
131
- color: #aaa;
132
- cursor: text;
133
- margin-bottom: 0px;
134
  }
1
+ /*
2
+ export-user-data.css
3
+
4
+ @since 0.9.6
5
+ */
6
+
7
+
8
+ /* general layout */
9
+
10
+ .form-table tr.remember div.row:first-child {
11
+ margin-bottom: 10px;
12
+ }
13
+
14
+ .form-table tr.remember input.button-primary {
15
+ margin-left: 5px;
16
+ }
17
+
18
+ .form-table tr.remember select {
19
+ width: 25em;
20
+ }
21
+
22
+ input.error {
23
+ background: #D54E21;
24
+ color: #fff;
25
+ border: 1px solid #CCC;
26
+ }
27
+
28
+ th p.filter {
29
+ width: 100%;
30
+ }
31
+
32
+ /* form inputs */
33
+
34
+
35
+ /* multiselects */
36
+
37
+ .ms-container{
38
+ background: transparent url('image/switch.png') no-repeat 50% 50%;
39
+ /* width: 600px; */
40
+ }
41
+
42
+ .ms-container:after{
43
+ content: ".";
44
+ display: block;
45
+ height: 0;
46
+ line-height: 0;
47
+ font-size: 0;
48
+ clear: both;
49
+ min-height: 0;
50
+ visibility: hidden;
51
+ }
52
+
53
+ .ms-container .ms-selectable, .ms-container .ms-selection{
54
+ background: #fff;
55
+ color: #555555;
56
+ float: left;
57
+ width: 45%;
58
+ }
59
+
60
+ .ms-container .ms-list{
61
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
62
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
63
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
64
+ -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
65
+ -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
66
+ -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
67
+ -o-transition: border linear 0.2s, box-shadow linear 0.2s;
68
+ transition: border linear 0.2s, box-shadow linear 0.2s;
69
+ border: 1px solid #ccc;
70
+ -webkit-border-radius: 3px;
71
+ -moz-border-radius: 3px;
72
+ border-radius: 3px;
73
+ position: relative;
74
+ height: 134px;
75
+ padding: 0;
76
+ overflow-y: auto;
77
+ overflow-x: hidden;
78
+ }
79
+
80
+ .ms-container .ms-selectable{
81
+ margin-right: 10%;
82
+ }
83
+
84
+ .ms-container .ms-list.ms-focus{
85
+ border-color: rgba(82, 168, 236, 0.8);
86
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
87
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
88
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
89
+ outline: 0;
90
+ outline: thin dotted \9;
91
+ }
92
+
93
+ .ms-container ul{
94
+ margin: 0;
95
+ list-style-type: none;
96
+ padding: 0;
97
+ }
98
+
99
+ .ms-container .ms-optgroup-container{
100
+ width: 100%;
101
+ }
102
+
103
+ .ms-container .ms-optgroup-label{
104
+ margin: 0;
105
+ padding: 5px 0px 0px 5px;
106
+ cursor: pointer;
107
+ color: #999;
108
+ }
109
+
110
+ .ms-container .ms-selectable li.ms-elem-selectable,
111
+ .ms-container .ms-selection li.ms-elem-selection{
112
+ border-bottom: 1px #eee solid;
113
+ padding: 4px 10px;
114
+ color: #555;
115
+ font-size: 14px;
116
+ margin-bottom: 0px;
117
+ }
118
+
119
+ .ms-container .ms-selectable li.ms-hover,
120
+ .ms-container .ms-selection li.ms-hover{
121
+ cursor: pointer;
122
+ color: #fff;
123
+ text-decoration: none;
124
+ background-color: #08c;
125
+ margin-bottom: 0px;
126
+ }
127
+
128
+ .ms-container .ms-selectable li.disabled,
129
+ .ms-container .ms-selection li.disabled{
130
+ background-color: #eee;
131
+ color: #aaa;
132
+ cursor: text;
133
+ margin-bottom: 0px;
134
  }
library/api/admin.php CHANGED
@@ -1,231 +1,231 @@
1
- <?php
2
-
3
- namespace q\report\api;
4
-
5
- use q\report\core\core as core;
6
- use q\report\core\helper as helper;
7
-
8
- // load it up ##
9
- #\q\report\api\admin::run();
10
-
11
- class admin extends \q_export_user_data {
12
-
13
- public static function run()
14
- {
15
-
16
- if ( \is_admin() ) {
17
-
18
- // load standard fields ##
19
- #\add_action( 'admin_init', array( get_class(), 'load' ), 1 );
20
-
21
- }
22
-
23
- }
24
-
25
-
26
-
27
- /**
28
- * Render admin fields
29
- *
30
- * @since 2.0.0.
31
- * @return HTML
32
- */
33
- public static function render( $array = null )
34
- {
35
-
36
- // check if we have any fields to show ##
37
- if (
38
- is_null( $array )
39
- || ! is_array( $array )
40
- ) {
41
-
42
- #helper::log( 'No fields found' );
43
-
44
- return false;
45
-
46
- }
47
-
48
- #helper::log( $array );
49
-
50
- // check that we have all required arrays ##
51
- if (
52
- ! $array['title'] // string ##
53
- || ! $array['label'] // lowercase string ##
54
- || ! $array['type']
55
- #|| ! $array['description']
56
- ) {
57
-
58
- #helper::log( 'Missing data' );
59
-
60
- return false;
61
-
62
- }
63
-
64
- // is this toggleable ? ##
65
- $toggleable = false === $array['title'] ? 'standard' : 'toggleable' ;
66
-
67
- // keep labels formatted nicely ##
68
- $array['label'] = \sanitize_key( $array['label'] );
69
-
70
- #helper::log( $array['options'] );
71
-
72
- // build out options ##
73
- if ( ! self::has_options( $array ) ) {
74
-
75
- #helper::log( 'Missing options for: '.$array['label'] );
76
-
77
- return false;
78
-
79
- }
80
-
81
- ?>
82
- <tr valign="top" class="<?php echo $toggleable; ?>">
83
- <th scope="row"><label for="q_report_<?php echo $array['label']; ?>"><?php echo $array['title']; ?></label></th>
84
- <td>
85
- <?php
86
-
87
- // options ##
88
- self::build_options( $array );
89
-
90
- // do we have a description ? ##
91
- if ( isset( $array['description'] ) ) {
92
-
93
- ?>
94
- <p class="description"><?php echo $array['description']; ?></p>
95
- <?php
96
-
97
- }
98
-
99
- ?>
100
- </td>
101
- </tr>
102
- <?php
103
-
104
- }
105
-
106
-
107
- public static function has_options( $array = null )
108
- {
109
-
110
- if (
111
- is_null( $array )
112
- || ! is_array( $array )
113
- || ! isset( $array['options'] )
114
- || ! isset( $array['label'] )
115
- || ! is_array( $array['options'] )
116
- || ! isset( $array['options_ID'] )
117
- || ! isset( $array['options_title'] )
118
- || ! isset( $array['label_select'] )
119
- ) {
120
-
121
- return false;
122
-
123
- }
124
-
125
- // crude ##
126
- return true;
127
-
128
- }
129
-
130
-
131
-
132
- public static function build_options( $array = null )
133
- {
134
-
135
- if (
136
- is_null( $array )
137
- || ! is_array( $array )
138
- || ! isset( $array['type'] )
139
- ) {
140
-
141
- #helper::log( 'Error building options for: '.$array['label'] );
142
-
143
- return false;
144
-
145
- }
146
-
147
- // start empty ##
148
- $return = false;
149
-
150
- switch ( $array['type'] ) {
151
-
152
- case ( 'select' ) :
153
-
154
- $return = self::field_select( $array );
155
-
156
- break ;
157
-
158
- }
159
-
160
- // kick it back ##
161
- return $return;
162
-
163
- }
164
-
165
-
166
-
167
- public static function field_select( $array = null )
168
- {
169
-
170
- if (
171
- is_null( $array )
172
- || ! is_array( $array )
173
- || ! isset( $array['options'] )
174
- || ! isset( $array['label'] )
175
- || ! is_array( $array['options'] )
176
- || ! isset( $array['options_ID'] )
177
- || ! isset( $array['options_title'] )
178
- || ! isset( $array['label_select'] )
179
- ) {
180
-
181
- #helper::log( 'Error building select options for: '.$array['label'] );
182
-
183
- return false;
184
-
185
- }
186
-
187
- #helper::log( 'Building select options for: '.$array['label'] );
188
-
189
- // is this a multiselect ? ##
190
- $multiselect = isset( $array['multiselect'] ) ? ' multiple="multiple"' : '' ;
191
-
192
- ?>
193
- <select <?php echo $multiselect; ?> name="<?php echo $array['label']; ?>" id="q_report_<?php echo $array['label']; ?>">
194
- <?php
195
-
196
- // label ##
197
- echo '<option value="">'.$array['label_select'].'</option>';
198
-
199
- // loop over all options ##
200
- foreach ( $array['options'] as $item ) {
201
-
202
- // id ##
203
- $id = $item->{$array['options_ID']}; // ID
204
-
205
- // title
206
- $title = $item->{$array['options_title']}; // post_title ##
207
-
208
- // check if option built ##
209
- if (
210
- ! $id
211
- || ! $title
212
- ) {
213
-
214
- continue;
215
-
216
- }
217
-
218
- ?>
219
- <option value='<?php echo \esc_attr( $id ); ?>'><?php echo $title; ?></option>
220
- <?php
221
-
222
- }
223
-
224
- ?>
225
- </select>
226
- <?php
227
-
228
- }
229
-
230
-
231
- }
1
+ <?php
2
+
3
+ namespace q\eud\api;
4
+
5
+ use q\eud\core\core as core;
6
+ use q\eud\core\helper as helper;
7
+
8
+ // load it up ##
9
+ #\q\eud\api\admin::run();
10
+
11
+ class admin extends \q_export_user_data {
12
+
13
+ public static function run()
14
+ {
15
+
16
+ if ( \is_admin() ) {
17
+
18
+ // load standard fields ##
19
+ #\add_action( 'admin_init', array( get_class(), 'load' ), 1 );
20
+
21
+ }
22
+
23
+ }
24
+
25
+
26
+
27
+ /**
28
+ * Render admin fields
29
+ *
30
+ * @since 2.0.0.
31
+ * @return HTML
32
+ */
33
+ public static function render( $array = null )
34
+ {
35
+
36
+ // check if we have any fields to show ##
37
+ if (
38
+ is_null( $array )
39
+ || ! is_array( $array )
40
+ ) {
41
+
42
+ #helper::log( 'No fields found' );
43
+
44
+ return false;
45
+
46
+ }
47
+
48
+ #helper::log( $array );
49
+
50
+ // check that we have all required arrays ##
51
+ if (
52
+ ! $array['title'] // string ##
53
+ || ! $array['label'] // lowercase string ##
54
+ || ! $array['type']
55
+ #|| ! $array['description']
56
+ ) {
57
+
58
+ #helper::log( 'Missing data' );
59
+
60
+ return false;
61
+
62
+ }
63
+
64
+ // is this toggleable ? ##
65
+ $toggleable = false === $array['title'] ? 'standard' : 'toggleable' ;
66
+
67
+ // keep labels formatted nicely ##
68
+ $array['label'] = \sanitize_key( $array['label'] );
69
+
70
+ #helper::log( $array['options'] );
71
+
72
+ // build out options ##
73
+ if ( ! self::has_options( $array ) ) {
74
+
75
+ #helper::log( 'Missing options for: '.$array['label'] );
76
+
77
+ return false;
78
+
79
+ }
80
+
81
+ ?>
82
+ <tr valign="top" class="<?php echo $toggleable; ?>">
83
+ <th scope="row"><label for="q_eud_<?php echo $array['label']; ?>"><?php echo $array['title']; ?></label></th>
84
+ <td>
85
+ <?php
86
+
87
+ // options ##
88
+ self::build_options( $array );
89
+
90
+ // do we have a description ? ##
91
+ if ( isset( $array['description'] ) ) {
92
+
93
+ ?>
94
+ <p class="description"><?php echo $array['description']; ?></p>
95
+ <?php
96
+
97
+ }
98
+
99
+ ?>
100
+ </td>
101
+ </tr>
102
+ <?php
103
+
104
+ }
105
+
106
+
107
+ public static function has_options( $array = null )
108
+ {
109
+
110
+ if (
111
+ is_null( $array )
112
+ || ! is_array( $array )
113
+ || ! isset( $array['options'] )
114
+ || ! isset( $array['label'] )
115
+ || ! is_array( $array['options'] )
116
+ || ! isset( $array['options_ID'] )
117
+ || ! isset( $array['options_title'] )
118
+ || ! isset( $array['label_select'] )
119
+ ) {
120
+
121
+ return false;
122
+
123
+ }
124
+
125
+ // crude ##
126
+ return true;
127
+
128
+ }
129
+
130
+
131
+
132
+ public static function build_options( $array = null )
133
+ {
134
+
135
+ if (
136
+ is_null( $array )
137
+ || ! is_array( $array )
138
+ || ! isset( $array['type'] )
139
+ ) {
140
+
141
+ #helper::log( 'Error building options for: '.$array['label'] );
142
+
143
+ return false;
144
+
145
+ }
146
+
147
+ // start empty ##
148
+ $return = false;
149
+
150
+ switch ( $array['type'] ) {
151
+
152
+ case ( 'select' ) :
153
+
154
+ $return = self::field_select( $array );
155
+
156
+ break ;
157
+
158
+ }
159
+
160
+ // kick it back ##
161
+ return $return;
162
+
163
+ }
164
+
165
+
166
+
167
+ public static function field_select( $array = null )
168
+ {
169
+
170
+ if (
171
+ is_null( $array )
172
+ || ! is_array( $array )
173
+ || ! isset( $array['options'] )
174
+ || ! isset( $array['label'] )
175
+ || ! is_array( $array['options'] )
176
+ || ! isset( $array['options_ID'] )
177
+ || ! isset( $array['options_title'] )
178
+ || ! isset( $array['label_select'] )
179
+ ) {
180
+
181
+ #helper::log( 'Error building select options for: '.$array['label'] );
182
+
183
+ return false;
184
+
185
+ }
186
+
187
+ #helper::log( 'Building select options for: '.$array['label'] );
188
+
189
+ // is this a multiselect ? ##
190
+ $multiselect = isset( $array['multiselect'] ) ? ' multiple="multiple"' : '' ;
191
+
192
+ ?>
193
+ <select <?php echo $multiselect; ?> name="<?php echo $array['label']; ?>" id="q_eud_<?php echo $array['label']; ?>">
194
+ <?php
195
+
196
+ // label ##
197
+ echo '<option value="">'.$array['label_select'].'</option>';
198
+
199
+ // loop over all options ##
200
+ foreach ( $array['options'] as $item ) {
201
+
202
+ // id ##
203
+ $id = $item->{$array['options_ID']}; // ID
204
+
205
+ // title
206
+ $title = $item->{$array['options_title']}; // post_title ##
207
+
208
+ // check if option built ##
209
+ if (
210
+ ! $id
211
+ || ! $title
212
+ ) {
213
+
214
+ continue;
215
+
216
+ }
217
+
218
+ ?>
219
+ <option value='<?php echo \esc_attr( $id ); ?>'><?php echo $title; ?></option>
220
+ <?php
221
+
222
+ }
223
+
224
+ ?>
225
+ </select>
226
+ <?php
227
+
228
+ }
229
+
230
+
231
+ }
library/core/buddypress.php CHANGED
@@ -1,99 +1,99 @@
1
- <?php
2
-
3
- namespace q\report\core;
4
-
5
- use q\report\core\core as core;
6
- use q\report\core\helper as helper;
7
-
8
- // load it up ##
9
- \q\report\core\buddypress::run();
10
-
11
- class buddypress extends \q_export_user_data {
12
-
13
- public static function run()
14
- {
15
-
16
- if ( \is_admin() ) {
17
-
18
- // load BP ##
19
- \add_action( 'admin_init', array( get_class(), 'load' ), 1000001 );
20
-
21
- }
22
-
23
- }
24
-
25
-
26
- /**
27
- * Get BP fields from DB, if BuddyPress is installed and active
28
- *
29
- * @since 2.0.0
30
- */
31
- public static function get_fields()
32
- {
33
-
34
- // buddypress support deprecated for now ##
35
- return false;
36
-
37
- if ( ! function_exists ('bp_is_active') ) {
38
-
39
- return false;
40
-
41
- }
42
-
43
- // introduce global class object ##
44
- global $wpdb;
45
-
46
- // grab all buddypress x profile fields ##
47
- $bp_fields = $wpdb->get_results( "SELECT distinct(name) FROM ".$wpdb->base_prefix."bp_xprofile_fields WHERE parent_id = 0" );
48
-
49
- // get name value from object ##
50
- $bp_fields = \wp_list_pluck( $bp_fields, 'name' );
51
-
52
- // test array ##
53
- #helper::log( $bp_fields );
54
-
55
- // allow array to be filtered ##
56
- $bp_fields = \apply_filters( 'export_user_data_bp_fields', $bp_fields );
57
-
58
- // kick it back ##
59
- return $bp_fields;
60
-
61
- }
62
-
63
-
64
-
65
- /**
66
- * Load up saved exports for this user
67
- * Set to public as hooked into action
68
- *
69
- * @since 0.9.6
70
- * @return Array of saved exports
71
- */
72
- public static function load()
73
- {
74
-
75
- // do we have a bp object in the globals ##
76
- if (
77
- \is_plugin_active( 'buddypress/bp-loader.php' ) // plugin active
78
- && function_exists ( 'buddypress' ) // loader function exists ##
79
- && ! isset( $GLOBALS['bp'] ) // but global unavailble ##
80
- ) {
81
-
82
- helper::log( 'BP not loaded - calling buddypress()' );
83
-
84
- // call BP
85
- buddypress();
86
-
87
- return true;
88
-
89
- }
90
-
91
- #self::log( 'BP loaded' );
92
-
93
- return true;
94
-
95
- }
96
-
97
-
98
-
99
- }
1
+ <?php
2
+
3
+ namespace q\eud\core;
4
+
5
+ use q\eud\core\core as core;
6
+ use q\eud\core\helper as helper;
7
+
8
+ // load it up ##
9
+ \q\eud\core\buddypress::run();
10
+
11
+ class buddypress extends \q_export_user_data {
12
+
13
+ public static function run()
14
+ {
15
+
16
+ if ( \is_admin() ) {
17
+
18
+ // load BP ##
19
+ \add_action( 'admin_init', array( get_class(), 'load' ), 1000001 );
20
+
21
+ }
22
+
23
+ }
24
+
25
+
26
+ /**
27
+ * Get BP fields from DB, if BuddyPress is installed and active
28
+ *
29
+ * @since 2.0.0
30
+ */
31
+ public static function get_fields()
32
+ {
33
+
34
+ // buddypress support deprecated for now ##
35
+ return false;
36
+
37
+ if ( ! function_exists ('bp_is_active') ) {
38
+
39
+ return false;
40
+
41
+ }
42
+
43
+ // introduce global class object ##
44
+ global $wpdb;
45
+
46
+ // grab all buddypress x profile fields ##
47
+ $bp_fields = $wpdb->get_results( "SELECT distinct(name) FROM ".$wpdb->base_prefix."bp_xprofile_fields WHERE parent_id = 0" );
48
+
49
+ // get name value from object ##
50
+ $bp_fields = \wp_list_pluck( $bp_fields, 'name' );
51
+
52
+ // test array ##
53
+ #helper::log( $bp_fields );
54
+
55
+ // allow array to be filtered ##
56
+ $bp_fields = \apply_filters( 'export_user_data_bp_fields', $bp_fields );
57
+
58
+ // kick it back ##
59
+ return $bp_fields;
60
+
61
+ }
62
+
63
+
64
+
65
+ /**
66
+ * Load up saved exports for this user
67
+ * Set to public as hooked into action
68
+ *
69
+ * @since 0.9.6
70
+ * @return Array of saved exports
71
+ */
72
+ public static function load()
73
+ {
74
+
75
+ // do we have a bp object in the globals ##
76
+ if (
77
+ \is_plugin_active( 'buddypress/bp-loader.php' ) // plugin active
78
+ && function_exists ( 'buddypress' ) // loader function exists ##
79
+ && ! isset( $GLOBALS['bp'] ) // but global unavailble ##
80
+ ) {
81
+
82
+ helper::log( 'BP not loaded - calling buddypress()' );
83
+
84
+ // call BP
85
+ buddypress();
86
+
87
+ return true;
88
+
89
+ }
90
+
91
+ #self::log( 'BP loaded' );
92
+
93
+ return true;
94
+
95
+ }
96
+
97
+
98
+
99
+ }
library/core/config.php CHANGED
@@ -1,88 +1,88 @@
1
- <?php
2
-
3
- namespace q\report\core;
4
-
5
- use q\report\core\core as core;
6
- use q\report\core\helper as helper;
7
-
8
- // load it up ##
9
- // \q\report\core\config::run();
10
-
11
- class config extends \q_export_user_data {
12
-
13
- public static function run()
14
- {
15
-
16
- if ( \is_admin() ) {
17
-
18
- // load standard fields ##
19
- \add_action( 'admin_init', array( get_class(), 'load' ), 1 );
20
-
21
- }
22
-
23
- }
24
-
25
-
26
-
27
- /**
28
- * Load up saved exports for this user
29
- * Set to public as hooked into action
30
- *
31
- * @since 0.9.6
32
- * @return Array of saved exports
33
- */
34
- public static function load()
35
- {
36
-
37
- // load api admin fields ##
38
- self::get_admin_fields();
39
-
40
- // kick it back ##
41
- return true;
42
-
43
- }
44
-
45
-
46
-
47
- /**
48
- * Load up saved exports for this user
49
- * Set to public as hooked into action
50
- *
51
- * @since 0.9.6
52
- * @return Array of saved exports
53
- */
54
- public static function get_admin_fields()
55
- {
56
-
57
- // build array ##
58
- $array = array(
59
- 'program' => array(
60
- 'title' => \_e( 'Programs', 'export-user-data' ),
61
- 'label' => 'program',
62
- 'description' => \__( 'Select the program that you wish to export.', 'export-user-data' ),
63
- 'label_select' => \__( 'All Programs', 'export-user-data' ),
64
- 'options' => \get_posts( array( 'post_type'=> 'program', 'posts_per_page' => -1 ) ),
65
- 'options_ID' => 'ID',
66
- 'options_title' => 'post_title'
67
- )
68
- );
69
-
70
- // test it ##
71
- #self::log( $array );
72
-
73
- // add to static property ##
74
- self::$api_admin_fields = $array;
75
-
76
- // filter and return ##
77
- apply_filters( 'q/report/api/admin_fields', self::$api_admin_fields );
78
-
79
- // test it ##
80
- self::log( self::$api_admin_fields );
81
-
82
- // kick it back ##
83
- return true;
84
-
85
- }
86
-
87
-
88
- }
1
+ <?php
2
+
3
+ namespace q\eud\core;
4
+
5
+ use q\eud\core\core as core;
6
+ use q\eud\core\helper as helper;
7
+
8
+ // load it up ##
9
+ // \q\eud\core\config::run();
10
+
11
+ class config extends \q_export_user_data {
12
+
13
+ public static function run()
14
+ {
15
+
16
+ if ( \is_admin() ) {
17
+
18
+ // load standard fields ##
19
+ \add_action( 'admin_init', array( get_class(), 'load' ), 1 );
20
+
21
+ }
22
+
23
+ }
24
+
25
+
26
+
27
+ /**
28
+ * Load up saved exports for this user
29
+ * Set to public as hooked into action
30
+ *
31
+ * @since 0.9.6
32
+ * @return Array of saved exports
33
+ */
34
+ public static function load()
35
+ {
36
+
37
+ // load api admin fields ##
38
+ self::get_admin_fields();
39
+
40
+ // kick it back ##
41
+ return true;
42
+
43
+ }
44
+
45
+
46
+
47
+ /**
48
+ * Load up saved exports for this user
49
+ * Set to public as hooked into action
50
+ *
51
+ * @since 0.9.6
52
+ * @return Array of saved exports
53
+ */
54
+ public static function get_admin_fields()
55
+ {
56
+
57
+ // build array ##
58
+ $array = array(
59
+ 'program' => array(
60
+ 'title' => \_e( 'Programs', 'export-user-data' ),
61
+ 'label' => 'program',
62
+ 'description' => \__( 'Select the program that you wish to export.', 'export-user-data' ),
63
+ 'label_select' => \__( 'All Programs', 'export-user-data' ),
64
+ 'options' => \get_posts( array( 'post_type'=> 'program', 'posts_per_page' => -1 ) ),
65
+ 'options_ID' => 'ID',
66
+ 'options_title' => 'post_title'
67
+ )
68
+ );
69
+
70
+ // test it ##
71
+ #self::log( $array );
72
+
73
+ // add to static property ##
74
+ self::$api_admin_fields = $array;
75
+
76
+ // filter and return ##
77
+ apply_filters( 'q/eud/api/admin_fields', self::$api_admin_fields );
78
+
79
+ // test it ##
80
+ self::log( self::$api_admin_fields );
81
+
82
+ // kick it back ##
83
+ return true;
84
+
85
+ }
86
+
87
+
88
+ }
library/core/core.php CHANGED
@@ -1,420 +1,426 @@
1
- <?php
2
-
3
- namespace q\report\core;
4
-
5
- use q\report\core\core as core;
6
- use q\report\core\helper as helper;
7
-
8
- // load it up ##
9
- #\q\report\core\core::run();
10
-
11
- class core extends \q_export_user_data {
12
-
13
- public static function run()
14
- {
15
-
16
- if ( \is_admin() ) {
17
-
18
- // load user options ##
19
- #\add_action( 'admin_init', array( get_class(), 'load_user_options' ), 1000002 );
20
-
21
- }
22
-
23
- }
24
-
25
-
26
-
27
- /**
28
- * Get the array of standard WP_User fields to return
29
- */
30
- public static function get_user_fields()
31
- {
32
-
33
- // standard wp_users fields ##
34
- if ( isset( $_POST['user_fields'] ) && '1' == $_POST['user_fields'] ) {
35
-
36
- // debug ##
37
- #self::log( 'full' );
38
-
39
- // exportable user data ##
40
- $user_fields = array(
41
- 'ID'
42
- , 'user_login'
43
- #, 'user_pass'
44
- , 'user_nicename'
45
- , 'user_email'
46
- , 'user_url'
47
- , 'user_registered'
48
- #, 'user_activation_key'
49
- , 'user_status'
50
- , 'display_name'
51
- );
52
-
53
- } else {
54
-
55
- // debug ##
56
- #self::log( 'reduced' );
57
-
58
- // just return the user ID
59
- $user_fields = array(
60
- 'ID'
61
- );
62
-
63
- }
64
-
65
- // kick back values via filter ##
66
- return \apply_filters( 'q/report/export/user_fields', $user_fields );
67
-
68
- }
69
-
70
-
71
-
72
-
73
- /**
74
- * Get the array of special user fields to return
75
- */
76
- public static function get_special_fields()
77
- {
78
-
79
- // exportable user data ##
80
- $special_fields = array(
81
- # 'roles' // list of WP Roles
82
- #, 'groups' // BP Groups
83
- );
84
-
85
- // should we allow groups ##
86
- if ( isset( $_POST['groups'] ) && '1' == $_POST['groups'] ) {
87
-
88
- $special_fields[] = 'groups'; // add groups ##
89
-
90
- }
91
-
92
- // should we allow roles ##
93
- if ( isset( $_POST['roles'] ) && '1' == $_POST['roles'] ) {
94
-
95
- $special_fields[] = 'roles'; // add groups ##
96
-
97
- }
98
-
99
- // kick back the array via filter ##
100
- return \apply_filters( 'q/report/export/special_fields', $special_fields );
101
-
102
- }
103
-
104
-
105
-
106
- /**
107
- * Data to exclude from export
108
- */
109
- public static function get_exclude_fields()
110
- {
111
-
112
- $exclude_fields = array (
113
- 'user_pass'
114
- , 'q_eud_exports'
115
- #, 'user_activation_key'
116
- );
117
-
118
- // kick back array via filter ##
119
- return \apply_filters( 'q/report/export/exclude_fields', $exclude_fields );
120
-
121
- }
122
-
123
-
124
-
125
-
126
- /**
127
- * Return Byte count of $val
128
- *
129
- * @link http://wordpress.org/support/topic/how-to-exporting-a-lot-of-data-out-of-memory-issue?replies=2
130
- * @since 0.9.6
131
- */
132
- public static function return_bytes( $val )
133
- {
134
-
135
- $val = trim( $val );
136
- $last = strtolower($val[strlen($val)-1]);
137
- switch( $last ) {
138
-
139
- // The 'G' modifier is available since PHP 5.1.0
140
- case 'g':
141
-
142
- $val *= 1024;
143
-
144
- case 'm':
145
-
146
- $val *= 1024;
147
-
148
- case 'k':
149
-
150
- $val *= 1024;
151
-
152
- }
153
-
154
- return $val;
155
-
156
- }
157
-
158
-
159
- /**
160
- * Recursively implodes an array
161
- *
162
- * @since 1.0.1
163
- * @access public
164
- * @param array $array multi-dimensional array to recursively implode
165
- * @param string $glue value that glues elements together
166
- * @param bool $include_keys include keys before their values
167
- * @param bool $trim_all trim ALL whitespace from string
168
- * @return string imploded array
169
- */
170
- public static function recursive_implode( $array, $return = null, $glue = '|' )
171
- {
172
-
173
- // unserialize ##
174
- $array = self::unserialize( $array );
175
-
176
- // kick it back ##
177
- if ( is_null ( $return ) && ! is_array( $array ) ) {
178
-
179
- return $array;
180
-
181
- }
182
-
183
- // empty return ##
184
- if ( is_null ( $return ) ) {
185
-
186
- $return = '';
187
-
188
- } else {
189
-
190
- if ( "||" == $glue ) {
191
-
192
- $glue = '|||';
193
-
194
- } else if ( "|" == $glue ) {
195
-
196
- $glue = '||';
197
-
198
- }
199
-
200
- }
201
-
202
- // loop ##
203
- foreach( $array as $key => $value ) {
204
-
205
- // unserialize ##
206
- $value = self::unserialize( $value );
207
-
208
- if( is_array( $value ) ) {
209
-
210
- $return .= $glue . $key . $glue . self::recursive_implode( $value, $return, $glue );
211
-
212
- } else {
213
-
214
- $return .= $glue . $key . $glue . $value;
215
-
216
- }
217
-
218
- }
219
-
220
- // Removes first $glue from string ##
221
- if ( $glue && $return && $return[0] == '|' ) {
222
-
223
- $return = ltrim( $return, '|' );
224
-
225
- }
226
-
227
- // Trim ALL whitespace ##
228
- if ( $return ) {
229
-
230
- $return = preg_replace( "/(\s)/ixsm", '', $return );
231
-
232
- }
233
-
234
- // kick it back ##
235
- return $return;
236
-
237
- }
238
-
239
-
240
-
241
-
242
- /**
243
- * Save Unserializer
244
- *
245
- * @since 1.1.4
246
- */
247
- public static function unserialize( $value = null )
248
- {
249
-
250
- // the $value is serialized ##
251
- if ( \is_serialized( $value ) ) {
252
-
253
- // unserliaze to new variable ##
254
- $unserialized = @unserialize( $value );
255
-
256
- // test if unserliazing produced errors ##
257
- if ( $unserialized !== false || $value == 'b:0;' ) {
258
-
259
- #$value = 'UNSERIALIZED_'.$unserialized;
260
- $value = $unserialized;
261
-
262
- } else {
263
-
264
- // failed to unserialize - data potentially corrupted in db ##
265
- #$value = 'NOT_SERIALIZED_'.$value;
266
- $value = $value;
267
-
268
- }
269
-
270
- }
271
-
272
- // kick it back ##
273
- return $value;
274
-
275
- }
276
-
277
-
278
-
279
-
280
- /**
281
- * Encode special characters
282
- *
283
- * @param type $string
284
- * @return string Encoding string
285
- * @since 1.2.3
286
- */
287
- public static function format_value( $string = null )
288
- {
289
-
290
- // sanity check ##
291
- if ( is_null( $string ) ) {
292
-
293
- return false;
294
-
295
- }
296
-
297
- // kick it back in a nicer format ##
298
- #return htmlentities( $string, ENT_COMPAT, 'UTF-8' );
299
-
300
- // kick it back via a filter to allow custom formatting ##
301
- return \apply_filters( 'q/report/export/format_value', $string );
302
-
303
- }
304
-
305
-
306
-
307
- /**
308
- * Quote array elements and separate with commas
309
- *
310
- * @since 0.9.6
311
- * @return String
312
- */
313
- public static function quote_array( $array )
314
- {
315
-
316
- $prefix = ''; // starts empty ##
317
- $elementlist = '';
318
-
319
- if ( is_array( $array ) ) {
320
-
321
- foreach( $array as $element ) {
322
-
323
- $elementlist .= $prefix . "'" . $element . "'";
324
- $prefix = ','; // prefix all remaining items with a comma ##
325
-
326
- }
327
-
328
- }
329
-
330
- // kick back string to function caller ##
331
- return( $elementlist );
332
-
333
- }
334
-
335
-
336
- /**
337
- * Export Date Options
338
- *
339
- * @since 0.9.6
340
- * @global type $wpdb
341
- * @return Array of objects
342
- */
343
- public static function get_user_registered_dates()
344
- {
345
-
346
- // invite in global objects ##
347
- global $wpdb;
348
-
349
- // query user table for oldest and newest registration ##
350
- $range =
351
- $wpdb->get_results (
352
- #$wpdb->prepare (
353
- "
354
- SELECT
355
- MIN( user_registered ) AS first,
356
- MAX( user_registered ) AS last
357
- FROM
358
- {$wpdb->users}
359
- "
360
- #)
361
- );
362
-
363
- return $range;
364
-
365
- }
366
-
367
-
368
-
369
- /**
370
- * Sanitize data
371
- *
372
- * @since 1.2.8
373
- * @return string
374
- */
375
- public static function sanitize( $value )
376
- {
377
-
378
- // emove line breaks ##
379
- $value = str_replace("\r", '', $value);
380
- $value = str_replace("\n", '', $value);
381
- $value = str_replace("\t", '', $value);
382
-
383
- // with wp_kses ##
384
- $value = \wp_kses( $value, self::get_allowed_tags() );
385
-
386
- // with esc_html
387
- $value = \esc_html( $value );
388
-
389
- // return value ##
390
- return $value;
391
-
392
- }
393
-
394
-
395
- /**
396
- * Get allowed tags for wp_kses
397
- *
398
- * @since 1.2.8
399
- * @return Array
400
- */
401
- public static function get_allowed_tags()
402
- {
403
-
404
- $allowed_tags = array(
405
- 'a' => array(
406
- 'href' => array(),
407
- 'title' => array()
408
- ),
409
- 'br' => array(),
410
- 'em' => array(),
411
- 'strong' => array(),
412
- );
413
-
414
- // kick back via filter ##
415
- return \apply_filters( 'q/report/export/allowed_tags', $allowed_tags );
416
-
417
- }
418
-
419
-
420
- }
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace q\eud\core;
4
+
5
+ use q\eud\core\core as core;
6
+ use q\eud\core\helper as helper;
7
+
8
+ // load it up ##
9
+ #\q\eud\core\core::run();
10
+
11
+ class core extends \q_export_user_data {
12
+
13
+ public static function run()
14
+ {
15
+
16
+ if ( \is_admin() ) {
17
+
18
+ // load user options ##
19
+ #\add_action( 'admin_init', array( get_class(), 'load_user_options' ), 1000002 );
20
+
21
+ }
22
+
23
+ }
24
+
25
+
26
+
27
+ /**
28
+ * Get the array of standard WP_User fields to return
29
+ */
30
+ public static function get_user_fields()
31
+ {
32
+
33
+ // standard wp_users fields ##
34
+ if ( isset( $_POST['user_fields'] ) && '1' == $_POST['user_fields'] ) {
35
+
36
+ // debug ##
37
+ #self::log( 'full' );
38
+
39
+ // exportable user data ##
40
+ $user_fields = array(
41
+ 'ID'
42
+ , 'user_login'
43
+ #, 'user_pass'
44
+ , 'user_nicename'
45
+ , 'user_email'
46
+ , 'user_url'
47
+ , 'user_registered'
48
+ #, 'user_activation_key'
49
+ , 'user_status'
50
+ , 'display_name'
51
+ );
52
+
53
+ } else {
54
+
55
+ // debug ##
56
+ #self::log( 'reduced' );
57
+
58
+ // just return the user ID
59
+ $user_fields = array(
60
+ 'ID'
61
+ );
62
+
63
+ }
64
+
65
+ // kick back values via filter ##
66
+ return \apply_filters( 'q/eud/export/user_fields', $user_fields );
67
+
68
+ }
69
+
70
+
71
+
72
+
73
+ /**
74
+ * Get the array of special user fields to return
75
+ */
76
+ public static function get_special_fields()
77
+ {
78
+
79
+ // exportable user data ##
80
+ $special_fields = array(
81
+ # 'roles' // list of WP Roles
82
+ #, 'groups' // BP Groups
83
+ );
84
+
85
+ // should we allow groups ##
86
+ if ( isset( $_POST['groups'] ) && '1' == $_POST['groups'] ) {
87
+
88
+ $special_fields[] = 'groups'; // add groups ##
89
+
90
+ }
91
+
92
+ // should we allow roles ##
93
+ if ( isset( $_POST['roles'] ) && '1' == $_POST['roles'] ) {
94
+
95
+ $special_fields[] = 'roles'; // add groups ##
96
+
97
+ }
98
+
99
+ // kick back the array via filter ##
100
+ return \apply_filters( 'q/eud/export/special_fields', $special_fields );
101
+
102
+ }
103
+
104
+
105
+
106
+ /**
107
+ * Data to exclude from export
108
+ */
109
+ public static function get_exclude_fields()
110
+ {
111
+
112
+ $exclude_fields = array (
113
+ 'user_pass'
114
+ , 'q_eud_exports'
115
+ #, 'user_activation_key'
116
+ );
117
+
118
+ // kick back array via filter ##
119
+ return \apply_filters( 'q/eud/export/exclude_fields', $exclude_fields );
120
+
121
+ }
122
+
123
+
124
+
125
+
126
+ /**
127
+ * Return Byte count of $val
128
+ *
129
+ * @link http://wordpress.org/support/topic/how-to-exporting-a-lot-of-data-out-of-memory-issue?replies=2
130
+ * @since 0.9.6
131
+ */
132
+ public static function return_bytes( $val )
133
+ {
134
+
135
+ $val = trim( $val );
136
+ $last = strtolower($val[strlen($val)-1]);
137
+ switch( $last ) {
138
+
139
+ // The 'G' modifier is available since PHP 5.1.0
140
+ case 'g':
141
+
142
+ $val *= 1024;
143
+
144
+ case 'm':
145
+
146
+ $val *= 1024;
147
+
148
+ case 'k':
149
+
150
+ $val *= 1024;
151
+
152
+ }
153
+
154
+ return $val;
155
+
156
+ }
157
+
158
+
159
+ /**
160
+ * Recursively implodes an array
161
+ *
162
+ * @since 1.0.1
163
+ * @access public
164
+ * @param array $array multi-dimensional array to recursively implode
165
+ * @param string $glue value that glues elements together
166
+ * @param bool $include_keys include keys before their values
167
+ * @param bool $trim_all trim ALL whitespace from string
168
+ * @return string imploded array
169
+ */
170
+ public static function recursive_implode( $array, $return = null, $glue = '|' )
171
+ {
172
+
173
+ // unserialize ##
174
+ $array = self::unserialize( $array );
175
+
176
+ // kick it back ##
177
+ if ( is_null ( $return ) && ! is_array( $array ) ) {
178
+
179
+ return $array;
180
+
181
+ }
182
+
183
+ // empty return ##
184
+ if ( is_null ( $return ) ) {
185
+
186
+ $return = '';
187
+
188
+ } else {
189
+
190
+ if ( "||" == $glue ) {
191
+
192
+ $glue = '|||';
193
+
194
+ } else if ( "|" == $glue ) {
195
+
196
+ $glue = '||';
197
+
198
+ }
199
+
200
+ }
201
+
202
+ // loop ##
203
+ foreach( $array as $key => $value ) {
204
+
205
+ // unserialize ##
206
+ $value = self::unserialize( $value );
207
+
208
+ if( is_array( $value ) ) {
209
+
210
+ $return .= $glue . $key . $glue . self::recursive_implode( $value, $return, $glue );
211
+
212
+ // add @2.1.0 from issue #4 - https://github.com/qstudio/export-user-data/issues/4
213
+ } elseif(is_object($value)) {
214
+
215
+ $return .= $glue . $key . $glue . self::recursive_implode( $value, $return, $glue );
216
+
217
+ } else {
218
+
219
+ $return .= $glue . $key . $glue . $value;
220
+
221
+ }
222
+
223
+
224
+ }
225
+
226
+ // Removes first $glue from string ##
227
+ if ( $glue && $return && $return[0] == '|' ) {
228
+
229
+ $return = ltrim( $return, '|' );
230
+
231
+ }
232
+
233
+ // Trim ALL whitespace ##
234
+ if ( $return ) {
235
+
236
+ $return = preg_replace( "/(\s)/ixsm", '', $return );
237
+
238
+ }
239
+
240
+ // kick it back ##
241
+ return $return;
242
+
243
+ }
244
+
245
+
246
+
247
+
248
+ /**
249
+ * Save Unserializer
250
+ *
251
+ * @since 1.1.4
252
+ */
253
+ public static function unserialize( $value = null )
254
+ {
255
+
256
+ // the $value is serialized ##
257
+ if ( \is_serialized( $value ) ) {
258
+
259
+ // unserliaze to new variable ##
260
+ $unserialized = @unserialize( $value );
261
+
262
+ // test if unserliazing produced errors ##
263
+ if ( $unserialized !== false || $value == 'b:0;' ) {
264
+
265
+ #$value = 'UNSERIALIZED_'.$unserialized;
266
+ $value = $unserialized;
267
+
268
+ } else {
269
+
270
+ // failed to unserialize - data potentially corrupted in db ##
271
+ #$value = 'NOT_SERIALIZED_'.$value;
272
+ $value = $value;
273
+
274
+ }
275
+
276
+ }
277
+
278
+ // kick it back ##
279
+ return $value;
280
+
281
+ }
282
+
283
+
284
+
285
+
286
+ /**
287
+ * Encode special characters
288
+ *
289
+ * @param type $string
290
+ * @return string Encoding string
291
+ * @since 1.2.3
292
+ */
293
+ public static function format_value( $string = null )
294
+ {
295
+
296
+ // sanity check ##
297
+ if ( is_null( $string ) ) {
298
+
299
+ return false;
300
+
301
+ }
302
+
303
+ // kick it back in a nicer format ##
304
+ #return htmlentities( $string, ENT_COMPAT, 'UTF-8' );
305
+
306
+ // kick it back via a filter to allow custom formatting ##
307
+ return \apply_filters( 'q/eud/export/format_value', $string );
308
+
309
+ }
310
+
311
+
312
+
313
+ /**
314
+ * Quote array elements and separate with commas
315
+ *
316
+ * @since 0.9.6
317
+ * @return String
318
+ */
319
+ public static function quote_array( $array )
320
+ {
321
+
322
+ $prefix = ''; // starts empty ##
323
+ $elementlist = '';
324
+
325
+ if ( is_array( $array ) ) {
326
+
327
+ foreach( $array as $element ) {
328
+
329
+ $elementlist .= $prefix . "'" . $element . "'";
330
+ $prefix = ','; // prefix all remaining items with a comma ##
331
+
332
+ }
333
+
334
+ }
335
+
336
+ // kick back string to function caller ##
337
+ return( $elementlist );
338
+
339
+ }
340
+
341
+
342
+ /**
343
+ * Export Date Options
344
+ *
345
+ * @since 0.9.6
346
+ * @global type $wpdb
347
+ * @return Array of objects
348
+ */
349
+ public static function get_user_registered_dates()
350
+ {
351
+
352
+ // invite in global objects ##
353
+ global $wpdb;
354
+
355
+ // query user table for oldest and newest registration ##
356
+ $range =
357
+ $wpdb->get_results (
358
+ #$wpdb->prepare (
359
+ "
360
+ SELECT
361
+ MIN( user_registered ) AS first,
362
+ MAX( user_registered ) AS last
363
+ FROM
364
+ {$wpdb->users}
365
+ "
366
+ #)
367
+ );
368
+
369
+ return $range;
370
+
371
+ }
372
+
373
+
374
+
375
+ /**
376
+ * Sanitize data
377
+ *
378
+ * @since 1.2.8
379
+ * @return string
380
+ */
381
+ public static function sanitize( $value )
382
+ {
383
+
384
+ // emove line breaks ##
385
+ $value = str_replace("\r", '', $value);
386
+ $value = str_replace("\n", '', $value);
387
+ $value = str_replace("\t", '', $value);
388
+
389
+ // with wp_kses ##
390
+ $value = \wp_kses( $value, self::get_allowed_tags() );
391
+
392
+ // with esc_html
393
+ $value = \esc_html( $value );
394
+
395
+ // return value ##
396
+ return $value;
397
+
398
+ }
399
+
400
+
401
+ /**
402
+ * Get allowed tags for wp_kses
403
+ *
404
+ * @since 1.2.8
405
+ * @return Array
406
+ */
407
+ public static function get_allowed_tags()
408
+ {
409
+
410
+ $allowed_tags = array(
411
+ 'a' => array(
412
+ 'href' => array(),
413
+ 'title' => array()
414
+ ),
415
+ 'br' => array(),
416
+ 'em' => array(),
417
+ 'strong' => array(),
418
+ );
419
+
420
+ // kick back via filter ##
421
+ return \apply_filters( 'q/eud/export/allowed_tags', $allowed_tags );
422
+
423
+ }
424
+
425
+
426
+ }
library/core/excel2003.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace q\eud\core;
4
+
5
+ use q\eud\core\core as core;
6
+ use q\eud\core\helper as helper;
7
+
8
+ /**
9
+ * XML template for excel file format
10
+ *
11
+ * @since 0.7.7
12
+ **/
13
+
14
+ class excel2003 extends \q_export_user_data {
15
+
16
+ public static function begin(){
17
+
18
+ $xml_doc_begin =
19
+ '<?xml version="1.0"?>
20
+ <?mso-application progid="Excel.Sheet"?>
21
+ <Workbook
22
+ xmlns="urn:schemas-microsoft-com:office:spreadsheet"
23
+ xmlns:o="urn:schemas-microsoft-com:office:office"
24
+ xmlns:x="urn:schemas-microsoft-com:office:excel"
25
+ xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
26
+ xmlns:html="http://www.w3.org/TR/REC-html40">
27
+ <Worksheet ss:Name="Exported Users">
28
+ <Table>';
29
+
30
+ return $xml_doc_begin;
31
+
32
+ }
33
+
34
+
35
+ public static function pre(){
36
+
37
+ $xml_pre =
38
+ '<Row>
39
+ <Cell>
40
+ <Data ss:Type="String">';
41
+
42
+ return $xml_pre;
43
+
44
+ }
45
+
46
+
47
+ public static function seperator(){
48
+
49
+ $xml_seperator =
50
+ '</Data>
51
+ </Cell>
52
+ <Cell>
53
+ <Data ss:Type="String">';
54
+
55
+ return $xml_seperator;
56
+
57
+ }
58
+
59
+
60
+ public static function breaker(){
61
+
62
+ $xml_breaker =
63
+ '</Data>
64
+ </Cell>
65
+ </Row>';
66
+
67
+ return $xml_breaker;
68
+
69
+ }
70
+
71
+
72
+ public static function end(){
73
+
74
+ $xml_doc_end = '
75
+ </Table>
76
+ </Worksheet>
77
+ </Workbook>';
78
+
79
+ return $xml_doc_end;
80
+
81
+ }
82
+
83
+ }
library/core/export.php CHANGED
@@ -1,607 +1,676 @@
1
- <?php
2
-
3
- namespace q\report\core;
4
-
5
- use q\report\core\core as core;
6
- use q\report\core\helper as helper;
7
- use q\report\core\xml as xml;
8
-
9
- // load it up ##
10
- \q\report\core\export::run();
11
-
12
- class export extends \q_export_user_data {
13
-
14
- public static function run()
15
- {
16
-
17
- if ( \is_admin() ) {
18
-
19
- // run export ##
20
- \add_action( 'admin_init', array( get_class(), 'render' ), 1000003 );
21
-
22
- }
23
-
24
- }
25
-
26
-
27
- /**
28
- * Attempt to generate the export file based on the passed arguements
29
- *
30
- * @since 0.1
31
- * @return Mixes
32
- **/
33
- public static function render()
34
- {
35
-
36
- // Check if the user clicked on the Save, Load, or Delete Settings buttons ##
37
- if (
38
- ! isset( $_POST['_wpnonce-q-report-admin-page'] )
39
- || isset( $_POST['load_export'] )
40
- || isset( $_POST['save_export'] )
41
- || isset( $_POST['delete_export'] ) )
42
- {
43
-
44
- return false;
45
-
46
- }
47
-
48
- // Increase maximum execution time to prevent "Maximum execution time exceeded" error ##
49
- ini_set( 'max_execution_time', -1 );
50
- ini_set( 'memory_limit', -1 ); // bad idea? ##
51
-
52
- // check admin referer ##
53
- \check_admin_referer( 'q-report-admin-page', '_wpnonce-q-report-admin-page' );
54
-
55
- // build argument array ##
56
- $args = array(
57
- 'fields' => ( isset( $_POST['user_fields'] ) && '1' == $_POST['user_fields'] ) ?
58
- 'all' :
59
- array( 'ID' ), // exclude standard wp_users fields from get_users query ##
60
- 'role' => \sanitize_text_field( $_POST['role'] )
61
- );
62
-
63
- // is there a range limit in place for the export ? ##
64
- if ( isset( $_POST['limit_total'] ) && '' != $_POST['limit_total'] ) {
65
-
66
- // let's just make sure they are integer values ##
67
- $limit_offset = isset( $_POST['limit_offset'] ) ? (int)$_POST['limit_offset'] : 0 ;
68
- $limit_total = (int)$_POST['limit_total'];
69
-
70
- if ( is_int( $limit_offset ) && is_int( $limit_total ) ) { // confirm we have integer values ##
71
-
72
- $args['offset'] = $limit_offset;
73
- $args['number'] = $limit_total; // number - Limit the total number of users returned ##
74
-
75
- // test it ##
76
- #if ( self::$debug )helper::log( $args );
77
-
78
- }
79
-
80
- }
81
-
82
- // add custom args via filters ##
83
- $args = \apply_filters( 'q/report/export/args', $args );
84
-
85
- #helper::log( $args );
86
-
87
- // pre_user query ##
88
- \add_action( 'pre_user_query', array( get_class(), 'pre_user_query' ) );
89
- $users = \get_users( $args );
90
- \remove_action( 'pre_user_query', array( get_class(), 'pre_user_query' ) );
91
-
92
- // test args ##
93
- #if ( self::$debug ) helper::log ( $users );
94
-
95
- // no users found, so chuck an error into the args array and exit the export ##
96
- if ( ! $users ) {
97
-
98
- \wp_redirect( \add_query_arg( 'error', 'empty', \wp_get_referer() ) );
99
- exit;
100
-
101
- }
102
-
103
- // get sitename and clean it up ##
104
- $sitename = \sanitize_key( \get_bloginfo( 'name' ) );
105
- if ( ! empty( $sitename ) ) {
106
- $sitename .= '.';
107
- }
108
-
109
- // export method ? ##
110
- $export_method = 'excel'; // default to Excel export ##
111
- if ( isset( $_POST['format'] ) && $_POST['format'] != '' ) {
112
-
113
- $export_method = \sanitize_text_field( $_POST['format'] );
114
-
115
- }
116
-
117
- // set export filename structure ##
118
- $filename = $sitename . 'report.' . date( 'Y-m-d-H-i-s' );
119
-
120
- switch ( $export_method ) {
121
-
122
- case ( 'csv' ):
123
-
124
- // to csv ##
125
- header( 'Content-Description: File Transfer' );
126
- header( 'Content-Disposition: attachment; filename='.$filename.'.csv' );
127
- header( 'Content-Type: text/csv; charset=' . \get_option( 'blog_charset' ), true );
128
-
129
- // set a csv check flag
130
- $is_csv = true;
131
-
132
- // nothing here
133
- $doc_begin = '';
134
-
135
- //preformat
136
- $pre = '';
137
-
138
- // how to seperate data ##
139
- $seperator = ','; // comma for csv ##
140
-
141
- // line break ##
142
- $breaker = "\n";
143
-
144
- // nothing here
145
- $doc_end = '';
146
-
147
- break;
148
-
149
- case ( 'excel' ):
150
-
151
- // to xls ##
152
- header( 'Content-Description: File Transfer' );
153
- header("Content-Type: application/vnd.ms-excel");
154
- header("Content-Disposition: attachment; filename=$filename.xls");
155
- header("Pragma: no-cache");
156
- header("Expires: 0");
157
-
158
- // set a csv check flag
159
- $is_csv = false;
160
-
161
- // open xml
162
- $doc_begin = xml::begin();
163
-
164
- //preformat
165
- $pre = xml::pre();
166
-
167
- // how to seperate data ##
168
- $seperator = xml::seperator();
169
-
170
- // line break ##
171
- $breaker = xml::breaker();
172
-
173
- // close xml
174
- $doc_end = xml::end();
175
-
176
- break;
177
-
178
- }
179
-
180
-
181
- // check for selected usermeta fields ##
182
- $usermeta = isset( $_POST['usermeta'] ) ? $_POST['usermeta']: '';
183
- #helper::log( $usermeta );
184
- $usermeta_fields = array();
185
-
186
- // loop over each field and sanitize ##
187
- if ( $usermeta && is_array( $usermeta ) ) {
188
- foreach( $usermeta as $field ) {
189
- $usermeta_fields[] = \sanitize_text_field ( $field );
190
- }
191
- }
192
-
193
- #helper::log( $usermeta_fields );
194
- #exit;
195
-
196
- // check for selected x profile fields ##
197
- $bp_fields = isset( $_POST['bp_fields'] ) ? $_POST['bp_fields'] : '';
198
- $bp_fields_passed = array();
199
- if ( $bp_fields && is_array( $bp_fields ) ) {
200
-
201
- foreach( $bp_fields as $field ) {
202
-
203
- // reverse tidy ##
204
- $field = str_replace( '__', ' ', \sanitize_text_field ( $field ) );
205
-
206
- // add to array ##
207
- $bp_fields_passed[] = $field;
208
-
209
- }
210
-
211
- }
212
-
213
- // cwjordan: check for x profile fields we want update time for ##
214
- $bp_fields_update = isset( $_POST['bp_fields_update_time'] ) ? $_POST['bp_fields_update_time'] : '';
215
- $bp_fields_update_passed = array();
216
- if ( $bp_fields_update && is_array( $bp_fields_update ) ) {
217
-
218
- foreach( $bp_fields_update as $field ) {
219
-
220
- // reverse tidy ##
221
- $field = str_replace( '__', ' ', \sanitize_text_field ( $field ) );
222
-
223
- // add to array ##
224
- $bp_fields_update_passed[] = $field . " Update Date";
225
-
226
- }
227
-
228
- }
229
-
230
- // global wpdb object ##
231
- global $wpdb;
232
-
233
- // debug ##
234
- #helper::log( 'merging array' );
235
-
236
- // compile final fields list ##
237
- $fields = array_merge(
238
- core::get_user_fields() // standard wp_user fields ##
239
- , core::get_special_fields() // 'special' fields - which are controlled via dedicated checks ##
240
- , $usermeta_fields // wp_user_meta fields ##
241
- , $bp_fields_passed // selected buddypress fields ##
242
- , $bp_fields_update_passed // update date for buddypress fields ##
243
- );
244
-
245
- // test field array ##
246
- #helper::log( $fields );
247
-
248
- // build the document headers ##
249
- $headers = array();
250
-
251
- foreach ( $fields as $key => $field ) {
252
-
253
- #helper::log( 'Field: '. $field );
254
-
255
- // filter field name ##
256
- $field = \apply_filters( 'q/report/export/field', $field );
257
-
258
- // grab fields to exclude from exports - filterable ##
259
- if ( in_array( $fields[$key], core::get_exclude_fields() ) ) {
260
-
261
- #helper::log( 'Dump Field: '. $fields[$key] );
262
-
263
- // ditch 'em ##
264
- unset( $fields[$key] );
265
-
266
- } else {
267
-
268
- if ( $is_csv ) {
269
-
270
- $headers[] = '"' . $field . '"';
271
-
272
- } else {
273
-
274
- $headers[] = $field;
275
-
276
- }
277
-
278
- }
279
-
280
- }
281
-
282
- // quick check ##
283
- #helper::log( $fields );
284
- #if ( self::$debug ) #helper::log( $bp_fields_passed );
285
-
286
- // no more buffering while spitting back the export data ##
287
- if( ob_get_level() > 0 ) ob_end_flush();
288
-
289
- // get the value in bytes allocated for Memory via php.ini ##
290
- // @link http://wordpress.org/support/topic/how-to-exporting-a-lot-of-data-out-of-memory-issue
291
- $memory_limit = core::return_bytes( ini_get('memory_limit') ) * .75;
292
-
293
- // we need to disable caching while exporting because we export so much data that it could blow the memory cache
294
- // if we can't override the cache here, we'll have to clear it later...
295
- if ( function_exists( 'override_function' ) ) {
296
-
297
- override_function('wp_cache_add', '$key, $data, $group="", $expire=0', '');
298
- override_function('wp_cache_set', '$key, $data, $group="", $expire=0', '');
299
- override_function('wp_cache_replace', '$key, $data, $group="", $expire=0', '');
300
- override_function('wp_cache_add_non_persistent_groups', '$key, $data, $group="", $expire=0', '');
301
-
302
- } elseif ( function_exists( 'runkit_function_redefine' ) ) {
303
-
304
- runkit_function_redefine('wp_cache_add', '$key, $data, $group="", $expire=0', '');
305
- runkit_function_redefine('wp_cache_set', '$key, $data, $group="", $expire=0', '');
306
- runkit_function_redefine('wp_cache_replace', '$key, $data, $group="", $expire=0', '');
307
- runkit_function_redefine('wp_cache_add_non_persistent_groups', '$key, $data, $group="", $expire=0', '');
308
-
309
- }
310
-
311
- // open doc wrapper.. ##
312
- echo $doc_begin;
313
-
314
- // echo headers ##
315
- echo $pre . implode( $seperator, $headers ) . $breaker;
316
-
317
- #helper::log( $users );
318
-
319
- // build row values for each user ##
320
- foreach ( $users as $user ) {
321
-
322
- #helper::log( $user );
323
-
324
- // check if we're hitting any Memory limits, if so flush them out ##
325
- // per http://wordpress.org/support/topic/how-to-exporting-a-lot-of-data-out-of-memory-issue?replies=2
326
- if ( memory_get_usage( true ) > $memory_limit ) {
327
- \wp_cache_flush();
328
- }
329
-
330
- // open up a new empty array ##
331
- $data = array();
332
-
333
- // BP loaded ? ##
334
- if (
335
- ! self::$bp_data_available
336
- && function_exists ( 'bp_is_active' )
337
- && \bp_is_active( 'xprofile' )
338
- && class_exists( 'BP_XProfile_ProfileData' )
339
- && method_exists( 'BP_XProfile_ProfileData', 'get_all_for_user' )
340
- && is_callable ( array( 'BP_XProfile_ProfileData', 'get_all_for_user' ) )
341
- ) {
342
-
343
- helper::log( 'XProfile Accessible' );
344
- self::$bp_data_available = true; // we only need to check for BP once ##
345
-
346
- }
347
-
348
- // grab all user data ##
349
- if (
350
- self::$bp_data_available
351
- && ! $bp_data = \BP_XProfile_ProfileData::get_all_for_user( $user->ID )
352
- ) {
353
-
354
- // null the data to be sure ##
355
- $bp_data = false;
356
-
357
- helper::log( 'XProfile returned no data ID#: '.$user->ID );
358
-
359
- }
360
-
361
- // single query method - get all user_meta data ##
362
- $get_user_meta = (array)\get_user_meta( $user->ID );
363
- #helper::log( $get_user_meta );
364
-
365
- // loop over each field ##
366
- foreach ( $fields as $field ) {
367
-
368
- // check if this is a BP field ##
369
- if (
370
- isset( $bp_data )
371
- && isset( $bp_data[$field] )
372
- && in_array( $field, $bp_fields_passed )
373
- ){
374
-
375
- // old way from single BP query ##
376
- $value = $bp_data[$field];
377
-
378
- if ( is_array( $value ) ) {
379
-
380
- $value = \maybe_unserialize( $value['field_data'] ); // suggested by @grexican ##
381
- #$value = $value['field_data'];
382
-
383
- /**
384
- * cwjordan
385
- * after unserializing it we then
386
- * need to implode it so
387
- * that we have something readable?
388
- * Going to use :: as a separator
389
- * because that's what Buddypress Members Import
390
- * expects, but we might want to make that
391
- * configurable.
392
- */
393
- if ( is_array( $value ) ) {
394
- $value = implode( "::", $value );
395
- }
396
-
397
- }
398
-
399
- // sanitize ##
400
- #$value = $this->sanitize($value);
401
-
402
- // check if this is a BP field we want the updated date for ##
403
- }
404
- elseif ( in_array( $field, $bp_fields_update_passed ) )
405
- {
406
-
407
- global $bp;
408
-
409
- $real_field = str_replace(" Update Date", "", $field);
410
- $field_id = \xprofile_get_field_id_from_name( $real_field );
411
- $value = $wpdb->get_var (
412
- $wpdb->prepare(
413
- "
414
- SELECT last_updated
415
- FROM {$bp->profile->table_name_data}
416
- WHERE user_id = %d AND field_id = %d
417
- "
418
- , $user->ID
419
- , $field_id
420
- )
421
- );
422
-
423
- // include the user's role in the export ##
424
- }
425
- elseif ( isset( $_POST['roles'] ) && '1' == $_POST['roles'] && $field == 'roles' )
426
- {
427
-
428
- // add "Role" as $value ##
429
- $value = isset( $user->roles[0] ) ? implode( $user->roles, '|' ) : '' ; // empty value if no role found - or flat array of user roles ##
430
-
431
- // include the user's BP group in the export ##
432
- }
433
- elseif ( isset( $_POST['groups'] ) && '1' == $_POST['groups'] && $field == 'groups' )
434
- {
435
-
436
- if ( function_exists( 'groups_get_user_groups' ) ) {
437
-
438
- // check if user is a member of any groups ##
439
- $group_ids = \groups_get_user_groups( $user->ID );
440
-
441
- #$this->pr( $group_ids );
442
- #wp_die( pr( 'loaded group data.' ));
443
-
444
- if ( ! $group_ids || $group_ids == '' ) {
445
-
446
- $value = '';
447
-
448
- } else {
449
-
450
- // new empty array ##
451
- $groups = array();
452
-
453
- // loop over all groups ##
454
- foreach( $group_ids["groups"] as $group_id ) {
455
-
456
- $groups[] = \groups_get_group( array( 'group_id' => $group_id )) -> name . ( end( $group_ids["groups"] ) == $group_id ? '' : '' );
457
-
458
- }
459
-
460
- // implode it ##
461
- $value = implode( $groups, '|' );
462
-
463
- }
464
-
465
- } else {
466
-
467
- $value = '';
468
-
469
- }
470
-
471
- }
472
- elseif ( $field == 'bp_latest_update' || $field == 'last_activity' )
473
- {
474
-
475
- // https://bpdevel.wordpress.com/2014/02/21/user-last_activity-data-and-buddypress-2-0/ ##
476
- $value = \bp_get_user_last_activity( $user->ID );
477
-
478
- // user or usermeta field ##
479
- }
480
- else
481
- {
482
-
483
- // the user_meta key isset ##
484
- if ( isset( $get_user_meta[$field] ) ) {
485
-
486
- // take from the bulk get_user_meta call - this returns an array in all cases, so we take the first key ##
487
- $value = $get_user_meta[$field][0];
488
-
489
- // standard WP_User value ##
490
- } else {
491
-
492
- // use the magically assigned value from WP_Users
493
- $value = isset( $user->{$field} ) ? $user->{$field} : null ;
494
-
495
- }
496
-
497
-
498
- // the $value might be serialized ##
499
- $value = core::unserialize( $value );
500
-
501
- // the value is an array ##
502
- if ( is_array ( $value ) ) {
503
-
504
- // recursive implode it ##
505
- $value = core::recursive_implode( $value );
506
-
507
- }
508
-
509
- // sanitize ##
510
- #$value = $this->sanitize($value);
511
-
512
- }
513
-
514
- // filter $value ##
515
- $value = \apply_filters( 'q/report/export/value', $value, $field );
516
-
517
- // sanitize ##
518
- $value = core::sanitize( $value );
519
-
520
- // wrap values in quotes and add to array ##
521
- if ( $is_csv ) {
522
-
523
- $data[] = '"' . str_replace( '"', '""', core::format_value( $value ) ) . '"';
524
-
525
- // just add to array ##
526
- } else {
527
-
528
- $data[] = core::format_value( $value );
529
- }
530
-
531
- }
532
-
533
- // echo row data ##
534
- echo $pre . implode( $seperator, $data ) . $breaker;
535
-
536
- }
537
-
538
- // close doc wrapper..
539
- echo $doc_end;
540
-
541
- // stop PHP, so file can export correctly ##
542
- exit;
543
-
544
- }
545
-
546
-
547
-
548
-
549
- /**
550
- * Pre User Query
551
- *
552
- * @since 2.0.0
553
- */
554
- public static function pre_user_query( $user_search = null )
555
- {
556
-
557
- global $wpdb;
558
-
559
- $where = '';
560
-
561
- if ( ! empty( $_POST['start_date'] ) ) {
562
-
563
- $date = new \DateTime( \sanitize_text_field ( $_POST['start_date'] ). ' 00:00:00' );
564
- $date_formatted = $date->format( 'Y-m-d H:i:s' );
565
-
566
- $where .= $wpdb->prepare( " AND $wpdb->users.user_registered >= %s", $date_formatted );
567
-
568
- }
569
- if ( ! empty( $_POST['end_date'] ) ) {
570
-
571
- $date = new \DateTime( \sanitize_text_field ( $_POST['end_date'] ). ' 00:00:00' );
572
- $date_formatted = $date->format( 'Y-m-d H:i:s' );
573
-
574
- $where .= $wpdb->prepare( " AND $wpdb->users.user_registered < %s", $date_formatted );
575
-
576
- }
577
-
578
- // search by last update time of BP extended fields ##
579
- if (
580
- class_exists( 'BP_Xprofile_Field' )
581
- && ( isset ($_POST['updated_since_date'] ) && $_POST['updated_since_date'] != '' )
582
- && (isset ($_POST['bp_field_updated_since'] ) && $_POST['bp_field_updated_since'] != '' )
583
- ) {
584
-
585
- $last_updated_date = new \DateTime( \sanitize_text_field ( $_POST['updated_since_date'] ) . ' 00:00:00' );
586
- self::$updated_since_date = $last_updated_date->format( 'Y-m-d H:i:s' );
587
- self::$field_updated_since = \sanitize_text_field ( $_POST['bp_field_updated_since'] );
588
- $field_updated_since_id = \BP_Xprofile_Field::get_id_from_name( self::$field_updated_since );
589
- $user_search->query_from .= " JOIN `wp_bp_xprofile_data` XP ON XP.user_id = wp_users.ID ";
590
- $where .= $wpdb->prepare( " AND XP.field_id = %s AND XP.last_updated >= %s", $field_updated_since_id, self::$updated_since_date );
591
-
592
- }
593
-
594
- if ( ! empty( $where ) ) {
595
-
596
- $user_search->query_where = str_replace( 'WHERE 1=1', "WHERE 1=1 $where", $user_search->query_where );
597
-
598
- }
599
-
600
- #wp_die( self::$pr( $user_search ) );
601
- return $user_search;
602
-
603
- }
604
-
605
-
606
-
607
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace q\eud\core;
4
+
5
+ use q\eud\core\core as core;
6
+ use q\eud\core\helper as helper;
7
+ // use q\eud\core\excel2003 as excel2003;
8
+ use XLSXWriter;
9
+
10
+ // load it up ##
11
+ \q\eud\core\export::run();
12
+
13
+ class export extends \q_export_user_data {
14
+
15
+ public static function run()
16
+ {
17
+
18
+ if ( \is_admin() ) {
19
+
20
+ // run export ##
21
+ \add_action( 'admin_init', array( get_class(), 'render' ), 1000003 );
22
+
23
+ }
24
+
25
+ }
26
+
27
+
28
+ /**
29
+ * Attempt to generate the export file based on the passed arguements
30
+ *
31
+ * @since 0.1
32
+ * @return Mixes
33
+ **/
34
+ public static function render()
35
+ {
36
+
37
+ // Check if the user clicked on the Save, Load, or Delete Settings buttons ##
38
+ if (
39
+ ! isset( $_POST['_wpnonce-q-eud-admin-page'] )
40
+ || isset( $_POST['load_export'] )
41
+ || isset( $_POST['save_export'] )
42
+ || isset( $_POST['delete_export'] ) )
43
+ {
44
+
45
+ return false;
46
+
47
+ }
48
+
49
+ // Increase maximum execution time to prevent "Maximum execution time exceeded" error ##
50
+ ini_set( 'max_execution_time', -1 );
51
+ ini_set( 'memory_limit', -1 ); // bad idea? ##
52
+
53
+ // check admin referer ##
54
+ \check_admin_referer( 'q-eud-admin-page', '_wpnonce-q-eud-admin-page' );
55
+
56
+ // build argument array ##
57
+ $args = array(
58
+ 'fields' => ( isset( $_POST['user_fields'] ) && '1' == $_POST['user_fields'] ) ?
59
+ 'all' :
60
+ array( 'ID' ), // exclude standard wp_users fields from get_users query ##
61
+ 'role' => \sanitize_text_field( $_POST['role'] )
62
+ );
63
+
64
+ // is there a range limit in place for the export ? ##
65
+ if ( isset( $_POST['limit_total'] ) && '' != $_POST['limit_total'] ) {
66
+
67
+ // let's just make sure they are integer values ##
68
+ $limit_offset = isset( $_POST['limit_offset'] ) ? (int)$_POST['limit_offset'] : 0 ;
69
+ $limit_total = (int)$_POST['limit_total'];
70
+
71
+ if ( is_int( $limit_offset ) && is_int( $limit_total ) ) { // confirm we have integer values ##
72
+
73
+ $args['offset'] = $limit_offset;
74
+ $args['number'] = $limit_total; // number - Limit the total number of users returned ##
75
+
76
+ // test it ##
77
+ helper::log( $args );
78
+
79
+ }
80
+
81
+ }
82
+
83
+ // add custom args via filters ##
84
+ $args = \apply_filters( 'q/eud/export/args', $args );
85
+
86
+ #helper::log( $args );
87
+
88
+ // pre_user query ##
89
+ \add_action( 'pre_user_query', array( get_class(), 'pre_user_query' ) );
90
+ $users = \get_users( $args );
91
+ \remove_action( 'pre_user_query', array( get_class(), 'pre_user_query' ) );
92
+
93
+ // test args ##
94
+ #if ( self::$debug ) helper::log ( $users );
95
+
96
+ // no users found, so chuck an error into the args array and exit the export ##
97
+ if ( ! $users ) {
98
+
99
+ \wp_redirect( \add_query_arg( 'error', 'empty', \wp_get_referer() ) );
100
+ exit;
101
+
102
+ }
103
+
104
+ // get sitename and clean it up ##
105
+ $sitename = \sanitize_key( \get_bloginfo( 'name' ) );
106
+ if ( ! empty( $sitename ) ) {
107
+ $sitename .= '.';
108
+ }
109
+
110
+ // export method ? ##
111
+ $export_method = 'excel2007'; // default to Excel export ##
112
+ if ( isset( $_POST['format'] ) && $_POST['format'] != '' ) {
113
+
114
+ $export_method = \sanitize_text_field( $_POST['format'] );
115
+
116
+ }
117
+
118
+ // set export filename structure ##
119
+ $filename = $sitename . 'report.' . date( 'Y-m-d-H-i-s' );
120
+
121
+ switch ( $export_method ) {
122
+
123
+ case ( 'csv' ):
124
+
125
+ // to csv ##
126
+ header( 'Content-Description: File Transfer' );
127
+ header( 'Content-Disposition: attachment; filename='.$filename.'.csv' );
128
+ header( 'Content-Type: text/csv; charset=' . \get_option( 'blog_charset' ), true );
129
+
130
+ // set a csv check flag
131
+ $is_csv = true;
132
+
133
+ // nothing here
134
+ $doc_begin = '';
135
+
136
+ //preformat
137
+ $pre = '';
138
+
139
+ // how to seperate data ##
140
+ $seperator = ','; // comma for csv ##
141
+
142
+ // line break ##
143
+ $breaker = "\n";
144
+
145
+ // nothing here
146
+ $doc_end = '';
147
+
148
+ break;
149
+
150
+ /*
151
+ case ( 'excel2003' ):
152
+
153
+ // to xls ##
154
+ header( 'Content-Description: File Transfer' );
155
+ header("Content-Type: application/vnd.ms-excel");
156
+ header("Content-Disposition: attachment; filename=$filename.xls");
157
+ header("Pragma: no-cache");
158
+ header("Expires: 0");
159
+
160
+ // set a csv check flag
161
+ $is_csv = false;
162
+
163
+ // open xml
164
+ $doc_begin = excel2003::begin();
165
+
166
+ //preformat
167
+ $pre = excel2003::pre();
168
+
169
+ // how to seperate data ##
170
+ $seperator = excel2003::seperator();
171
+
172
+ // line break ##
173
+ $breaker = excel2003::breaker();
174
+
175
+ // close xml
176
+ $doc_end = excel2003::end();
177
+
178
+ break;
179
+ */
180
+
181
+ case ( 'excel2007' ):
182
+
183
+ // to xlsx ##
184
+ header( 'Content-Description: File Transfer' );
185
+ header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
186
+ header("Content-Disposition: attachment; filename=$filename.xlsx");
187
+ header('Content-Transfer-Encoding: binary');
188
+ //header('Content-Length: ' . filesize($file));
189
+ //header('Cache-Control: must-revalidate');
190
+ //header('Pragma: public');
191
+ header("Pragma: no-cache");
192
+ header("Expires: 0");
193
+
194
+ // set a csv check flag
195
+ $is_csv = false;
196
+
197
+ // open xml
198
+ $doc_begin = "";
199
+ $pre = "";
200
+ $seperator = "";
201
+ $breaker = "";
202
+ $doc_end = "";
203
+
204
+ $writer = new XLSXWriter();
205
+
206
+ break;
207
+
208
+ }
209
+
210
+
211
+ // check for selected usermeta fields ##
212
+ $usermeta = isset( $_POST['usermeta'] ) ? $_POST['usermeta']: '';
213
+ #helper::log( $usermeta );
214
+ $usermeta_fields = array();
215
+
216
+ // loop over each field and sanitize ## @todo - user array_map ##
217
+ if ( $usermeta && is_array( $usermeta ) ) {
218
+ foreach( $usermeta as $field ) {
219
+ $usermeta_fields[] = \sanitize_text_field ( $field );
220
+ }
221
+ }
222
+
223
+ #helper::log( $usermeta_fields );
224
+ #exit;
225
+
226
+ // check for selected x profile fields ##
227
+ $bp_fields = isset( $_POST['bp_fields'] ) ? $_POST['bp_fields'] : '';
228
+ $bp_fields_passed = array();
229
+ if ( $bp_fields && is_array( $bp_fields ) ) {
230
+
231
+ foreach( $bp_fields as $field ) {
232
+
233
+ // reverse tidy ##
234
+ $field = str_replace( '__', ' ', \sanitize_text_field ( $field ) );
235
+
236
+ // add to array ##
237
+ $bp_fields_passed[] = $field;
238
+
239
+ }
240
+
241
+ }
242
+
243
+ // cwjordan: check for x profile fields we want update time for ##
244
+ $bp_fields_update = isset( $_POST['bp_fields_update_time'] ) ? $_POST['bp_fields_update_time'] : '';
245
+ $bp_fields_update_passed = array();
246
+ if ( $bp_fields_update && is_array( $bp_fields_update ) ) {
247
+
248
+ foreach( $bp_fields_update as $field ) {
249
+
250
+ // reverse tidy ##
251
+ $field = str_replace( '__', ' ', \sanitize_text_field ( $field ) );
252
+
253
+ // add to array ##
254
+ $bp_fields_update_passed[] = $field . " Update Date";
255
+
256
+ }
257
+
258
+ }
259
+
260
+ // global wpdb object ##
261
+ global $wpdb;
262
+
263
+ // debug ##
264
+ #helper::log( 'merging array' );
265
+
266
+ // compile final fields list ##
267
+ $fields = array_merge(
268
+ core::get_user_fields() // standard wp_user fields ##
269
+ , core::get_special_fields() // 'special' fields - which are controlled via dedicated checks ##
270
+ , $usermeta_fields // wp_user_meta fields ##
271
+ , $bp_fields_passed // selected buddypress fields ##
272
+ , $bp_fields_update_passed // update date for buddypress fields ##
273
+ );
274
+
275
+ // test field array ##
276
+ #helper::log( $fields );
277
+
278
+ // build the document headers ##
279
+ $headers = array();
280
+
281
+ foreach ( $fields as $key => $field ) {
282
+
283
+ #helper::log( 'Field: '. $field );
284
+
285
+ // filter field name ##
286
+ $field = \apply_filters( 'q/eud/export/field', $field );
287
+
288
+ // grab fields to exclude from exports - filterable ##
289
+ if ( in_array( $fields[$key], core::get_exclude_fields() ) ) {
290
+
291
+ #helper::log( 'Dump Field: '. $fields[$key] );
292
+
293
+ // ditch 'em ##
294
+ unset( $fields[$key] );
295
+
296
+ } else {
297
+
298
+ if ( $is_csv ) {
299
+
300
+ $headers[] = '"' . $field . '"';
301
+
302
+ } else {
303
+
304
+ $headers[] = $field;
305
+
306
+ }
307
+
308
+ }
309
+
310
+ }
311
+
312
+ // quick check ##
313
+ #helper::log( $fields );
314
+ #if ( self::$debug ) #helper::log( $bp_fields_passed );
315
+
316
+ // no more buffering while spitting back the export data ##
317
+ if( ob_get_level() > 0 ) ob_end_flush();
318
+
319
+ // get the value in bytes allocated for Memory via php.ini ##
320
+ // @link http://wordpress.org/support/topic/how-to-exporting-a-lot-of-data-out-of-memory-issue
321
+ $memory_limit = core::return_bytes( ini_get('memory_limit') ) * .75;
322
+
323
+ // we need to disable caching while exporting because we export so much data that it could blow the memory cache
324
+ // if we can't override the cache here, we'll have to clear it later...
325
+ if ( function_exists( 'override_function' ) ) {
326
+
327
+ override_function('wp_cache_add', '$key, $data, $group="", $expire=0', '');
328
+ override_function('wp_cache_set', '$key, $data, $group="", $expire=0', '');
329
+ override_function('wp_cache_replace', '$key, $data, $group="", $expire=0', '');
330
+ override_function('wp_cache_add_non_persistent_groups', '$key, $data, $group="", $expire=0', '');
331
+
332
+ } elseif ( function_exists( 'runkit_function_redefine' ) ) {
333
+
334
+ runkit_function_redefine('wp_cache_add', '$key, $data, $group="", $expire=0', '');
335
+ runkit_function_redefine('wp_cache_set', '$key, $data, $group="", $expire=0', '');
336
+ runkit_function_redefine('wp_cache_replace', '$key, $data, $group="", $expire=0', '');
337
+ runkit_function_redefine('wp_cache_add_non_persistent_groups', '$key, $data, $group="", $expire=0', '');
338
+
339
+ }
340
+
341
+
342
+ if ($export_method !== "excel2007") {
343
+ // open doc wrapper.. ##
344
+ echo $doc_begin;
345
+
346
+ // echo headers ##
347
+ echo $pre . implode( $seperator, $headers ) . $breaker;
348
+
349
+ #helper::log( $users );
350
+ } else {
351
+
352
+ $xlsx_header = array_flip($headers);
353
+
354
+ foreach($xlsx_header as $k => $v) {
355
+ $xlsx_header[$k] = "string";
356
+ }
357
+
358
+ $writer->writeSheetHeader('Sheet1', $xlsx_header);
359
+ }
360
+
361
+ // build row values for each user ##
362
+ foreach ( $users as $user ) {
363
+
364
+ #helper::log( $user );
365
+
366
+ // check if we're hitting any Memory limits, if so flush them out ##
367
+ // per http://wordpress.org/support/topic/how-to-exporting-a-lot-of-data-out-of-memory-issue?replies=2
368
+ if ( memory_get_usage( true ) > $memory_limit ) {
369
+ \wp_cache_flush();
370
+ }
371
+
372
+ // open up a new empty array ##
373
+ $data = array();
374
+
375
+ // BP loaded ? ##
376
+ if (
377
+ ! self::$bp_data_available
378
+ && function_exists ( 'bp_is_active' )
379
+ && \bp_is_active( 'xprofile' )
380
+ && class_exists( 'BP_XProfile_ProfileData' )
381
+ && method_exists( 'BP_XProfile_ProfileData', 'get_all_for_user' )
382
+ && is_callable ( array( 'BP_XProfile_ProfileData', 'get_all_for_user' ) )
383
+ ) {
384
+
385
+ helper::log( 'XProfile Accessible' );
386
+ self::$bp_data_available = true; // we only need to check for BP once ##
387
+
388
+ }
389
+
390
+ // grab all user data ##
391
+ if (
392
+ self::$bp_data_available
393
+ && ! $bp_data = \BP_XProfile_ProfileData::get_all_for_user( $user->ID )
394
+ ) {
395
+
396
+ // null the data to be sure ##
397
+ $bp_data = false;
398
+
399
+ helper::log( 'XProfile returned no data ID#: '.$user->ID );
400
+
401
+ }
402
+
403
+ // single query method - get all user_meta data ##
404
+ $get_user_meta = (array)\get_user_meta( $user->ID );
405
+ #helper::log( $get_user_meta );
406
+
407
+ // loop over each field ##
408
+ foreach ( $fields as $field ) {
409
+
410
+ // check if this is a BP field ##
411
+ if (
412
+ isset( $bp_data )
413
+ && isset( $bp_data[$field] )
414
+ && in_array( $field, $bp_fields_passed )
415
+ ){
416
+
417
+ // old way from single BP query ##
418
+ $value = $bp_data[$field];
419
+
420
+ if ( is_array( $value ) ) {
421
+
422
+ $value = \maybe_unserialize( $value['field_data'] ); // suggested by @grexican ##
423
+ #$value = $value['field_data'];
424
+
425
+ /**
426
+ * cwjordan
427
+ * after unserializing it we then
428
+ * need to implode it so
429
+ * that we have something readable?
430
+ * Going to use :: as a separator
431
+ * because that's what Buddypress Members Import
432
+ * expects, but we might want to make that
433
+ * configurable.
434
+ */
435
+ if ( is_array( $value ) ) {
436
+ $value = implode( "::", $value );
437
+ }
438
+
439
+ }
440
+
441
+ // sanitize ##
442
+ #$value = $this->sanitize($value);
443
+
444
+ // check if this is a BP field we want the updated date for ##
445
+ }
446
+ elseif ( in_array( $field, $bp_fields_update_passed ) )
447
+ {
448
+
449
+ global $bp;
450
+
451
+ $real_field = str_replace(" Update Date", "", $field);
452
+ $field_id = \xprofile_get_field_id_from_name( $real_field );
453
+ $value = $wpdb->get_var (
454
+ $wpdb->prepare(
455
+ "
456
+ SELECT last_updated
457
+ FROM {$bp->profile->table_name_data}
458
+ WHERE user_id = %d AND field_id = %d
459
+ "
460
+ , $user->ID
461
+ , $field_id
462
+ )
463
+ );
464
+
465
+ // include the user's role in the export ##
466
+ }
467
+ elseif ( isset( $_POST['roles'] ) && '1' == $_POST['roles'] && $field == 'roles' )
468
+ {
469
+
470
+ // empty array ##
471
+ $user_roles = [];
472
+
473
+ // get usermeta data
474
+ $userdata = \get_userdata( $user->ID );
475
+
476
+ // loop over roles, taking the name ##
477
+ foreach( $userdata->roles as $role ) {
478
+
479
+ $user_roles[] = \translate_user_role( $role );
480
+
481
+ }
482
+
483
+ // test ##
484
+ // helper::log( $user_roles );
485
+
486
+ // empty value if no role found - or flat array of user roles ##
487
+ $value = ! empty( $user_roles ) ? implode( $user_roles, '|' ) : '';
488
+
489
+ // include the user's BP group in the export ##
490
+ }
491
+ elseif ( isset( $_POST['groups'] ) && '1' == $_POST['groups'] && $field == 'groups' )
492
+ {
493
+
494
+ if ( function_exists( 'groups_get_user_groups' ) ) {
495
+
496
+ // check if user is a member of any groups ##
497
+ $group_ids = \groups_get_user_groups( $user->ID );
498
+
499
+ #$this->pr( $group_ids );
500
+ #wp_die( pr( 'loaded group data.' ));
501
+
502
+ if ( ! $group_ids || $group_ids == '' ) {
503
+
504
+ $value = '';
505
+
506
+ } else {
507
+
508
+ // new empty array ##
509
+ $groups = array();
510
+
511
+ // loop over all groups ##
512
+ foreach( $group_ids["groups"] as $group_id ) {
513
+
514
+ $groups[] = \groups_get_group( array( 'group_id' => $group_id )) -> name . ( end( $group_ids["groups"] ) == $group_id ? '' : '' );
515
+
516
+ }
517
+
518
+ // implode it ##
519
+ $value = implode( $groups, '|' );
520
+
521
+ }
522
+
523
+ } else {
524
+
525
+ $value = '';
526
+
527
+ }
528
+
529
+ }
530
+ elseif ( $field == 'bp_latest_update' || $field == 'last_activity' )
531
+ {
532
+
533
+ // https://bpdevel.wordpress.com/2014/02/21/user-last_activity-data-and-buddypress-2-0/ ##
534
+ $value = \bp_get_user_last_activity( $user->ID );
535
+
536
+ // user or usermeta field ##
537
+ }
538
+ else
539
+ {
540
+
541
+ // the user_meta key isset ##
542
+ if ( isset( $get_user_meta[$field] ) ) {
543
+
544
+ // take from the bulk get_user_meta call - this returns an array in all cases, so we take the first key ##
545
+ $value = $get_user_meta[$field][0];
546
+
547
+ // standard WP_User value ##
548
+ } else {
549
+
550
+ // use the magically assigned value from WP_Users
551
+ $value = isset( $user->{$field} ) ? $user->{$field} : null ;
552
+
553
+ }
554
+
555
+
556
+ // the $value might be serialized ##
557
+ $value = core::unserialize( $value );
558
+
559
+ // the value is an array ##
560
+ if ( is_array ( $value ) ) {
561
+
562
+ // recursive implode it ##
563
+ $value = core::recursive_implode( $value );
564
+
565
+ }
566
+
567
+ // sanitize ##
568
+ #$value = $this->sanitize($value);
569
+
570
+ }
571
+
572
+ // filter $value ##
573
+ $value = \apply_filters( 'q/eud/export/value', $value, $field );
574
+
575
+ // sanitize ##
576
+ $value = core::sanitize( $value );
577
+
578
+ // wrap values in quotes and add to array ##
579
+ if ( $is_csv ) {
580
+
581
+ $data[] = '"' . str_replace( '"', '""', core::format_value( $value ) ) . '"';
582
+
583
+ // just add to array ##
584
+ } else {
585
+
586
+ $data[] = core::format_value( $value );
587
+ }
588
+
589
+ }
590
+
591
+ if ($export_method !== "excel2007") {
592
+ // echo row data ##
593
+ echo $pre . implode( $seperator, $data ) . $breaker;
594
+ } else {
595
+ $writer->writeSheetRow('Sheet1', $data);
596
+ }
597
+
598
+ }
599
+
600
+ if ($export_method !== "excel2007") {
601
+ // close doc wrapper..
602
+ echo $doc_end;
603
+ } else {
604
+ //$writer->writeSheet($rows,'Sheet1', $header); //or write the whole sheet in 1 call
605
+ //$writer->writeToFile('xlsx-simple.xlsx');
606
+ //$writer->writeToStdOut();
607
+ echo $writer->writeToString();
608
+ }
609
+
610
+ // stop PHP, so file can export correctly ##
611
+ exit;
612
+
613
+ }
614
+
615
+
616
+
617
+
618
+ /**
619
+ * Pre User Query
620
+ *
621
+ * @since 2.0.0
622
+ */
623
+ public static function pre_user_query( $user_search = null )
624
+ {
625
+
626
+ global $wpdb;
627
+
628
+ $where = '';
629
+
630
+ if ( ! empty( $_POST['start_date'] ) ) {
631
+
632
+ $date = new \DateTime( \sanitize_text_field ( $_POST['start_date'] ). ' 00:00:00' );
633
+ $date_formatted = $date->format( 'Y-m-d H:i:s' );
634
+
635
+ $where .= $wpdb->prepare( " AND $wpdb->users.user_registered >= %s", $date_formatted );
636
+
637
+ }
638
+ if ( ! empty( $_POST['end_date'] ) ) {
639
+
640
+ $date = new \DateTime( \sanitize_text_field ( $_POST['end_date'] ). ' 00:00:00' );
641
+ $date_formatted = $date->format( 'Y-m-d H:i:s' );
642
+
643
+ $where .= $wpdb->prepare( " AND $wpdb->users.user_registered < %s", $date_formatted );
644
+
645
+ }
646
+
647
+ // search by last update time of BP extended fields ##
648
+ if (
649
+ class_exists( 'BP_Xprofile_Field' )
650
+ && ( isset ($_POST['updated_since_date'] ) && $_POST['updated_since_date'] != '' )
651
+ && (isset ($_POST['bp_field_updated_since'] ) && $_POST['bp_field_updated_since'] != '' )
652
+ ) {
653
+
654
+ $last_updated_date = new \DateTime( \sanitize_text_field ( $_POST['updated_since_date'] ) . ' 00:00:00' );
655
+ self::$updated_since_date = $last_updated_date->format( 'Y-m-d H:i:s' );
656
+ self::$field_updated_since = \sanitize_text_field ( $_POST['bp_field_updated_since'] );
657
+ $field_updated_since_id = \BP_Xprofile_Field::get_id_from_name( self::$field_updated_since );
658
+ $user_search->query_from .= " JOIN `wp_bp_xprofile_data` XP ON XP.user_id = wp_users.ID ";
659
+ $where .= $wpdb->prepare( " AND XP.field_id = %s AND XP.last_updated >= %s", $field_updated_since_id, self::$updated_since_date );
660
+
661
+ }
662
+
663
+ if ( ! empty( $where ) ) {
664
+
665
+ $user_search->query_where = str_replace( 'WHERE 1=1', "WHERE 1=1 $where", $user_search->query_where );
666
+
667
+ }
668
+
669
+ #wp_die( self::$pr( $user_search ) );
670
+ return $user_search;
671
+
672
+ }
673
+
674
+
675
+
676
+ }
library/core/filters.php CHANGED
@@ -1,59 +1,59 @@
1
- <?php
2
-
3
- namespace q\report\core;
4
-
5
- use q\report\core\core as core;
6
- use q\report\core\helper as helper;
7
-
8
- // load it up ##
9
- \q\report\core\filters::run();
10
-
11
- class filters extends \q_export_user_data {
12
-
13
- public static function run()
14
- {
15
-
16
- if ( \is_admin() ) {
17
-
18
- // EUD - filter key shown ##
19
- \add_filter( 'q/report/admin/display_key', [ get_class(), 'display_key' ], 1, 1 );
20
-
21
- }
22
-
23
- }
24
-
25
-
26
- /**
27
- * Filter keys in EUD plugin
28
- *
29
- * @since 2.0.0
30
- */
31
- public static function display_key( $string = null )
32
- {
33
-
34
- #helper::log( 'string from filter: '.$string );
35
-
36
- if ( is_null( $string ) ) {
37
-
38
- return false;
39
-
40
- }
41
-
42
- // array of translations ##
43
- $array = [
44
- 'first_name' => 'First Name',
45
- ];
46
-
47
- // check if $string exists as key in $array and if so, replace and return ##
48
- if ( array_key_exists( $string, $array ) ) {
49
-
50
- return $array[$string];
51
-
52
- }
53
-
54
- // kick it back ##
55
- return $string;
56
-
57
- }
58
-
59
- }
1
+ <?php
2
+
3
+ namespace q\eud\core;
4
+
5
+ use q\eud\core\core as core;
6
+ use q\eud\core\helper as helper;
7
+
8
+ // load it up ##
9
+ \q\eud\core\filters::run();
10
+
11
+ class filters extends \q_export_user_data {
12
+
13
+ public static function run()
14
+ {
15
+
16
+ if ( \is_admin() ) {
17
+
18
+ // EUD - filter key shown ##
19
+ \add_filter( 'q/eud/admin/display_key', [ get_class(), 'display_key' ], 1, 1 );
20
+
21
+ }
22
+
23
+ }
24
+
25
+
26
+ /**
27
+ * Filter keys in EUD plugin
28
+ *
29
+ * @since 2.0.0
30
+ */
31
+ public static function display_key( $string = null )
32
+ {
33
+
34
+ #helper::log( 'string from filter: '.$string );
35
+
36
+ if ( is_null( $string ) ) {
37
+
38
+ return false;
39
+
40
+ }
41
+
42
+ // array of translations ##
43
+ $array = [
44
+ 'first_name' => 'First Name',
45
+ ];
46
+
47
+ // check if $string exists as key in $array and if so, replace and return ##
48
+ if ( array_key_exists( $string, $array ) ) {
49
+
50
+ return $array[$string];
51
+
52
+ }
53
+
54
+ // kick it back ##
55
+ return $string;
56
+
57
+ }
58
+
59
+ }
library/core/helper.php CHANGED
@@ -1,49 +1,46 @@
1
- <?php
2
-
3
- // namespace ##
4
- namespace q\report\core;
5
-
6
- // piggyback Q helper ##
7
- use q\core\helper as q_helper;
8
-
9
- /**
10
- * helper Class
11
- * @package q_report\core
12
- */
13
- class helper extends \q_export_user_data {
14
-
15
-
16
- /**
17
- * Write to WP Error Log
18
- *
19
- * @since 1.5.0
20
- * @return void
21
- */
22
- public static function log( $log )
23
- {
24
-
25
- if ( true === WP_DEBUG ) {
26
-
27
- $trace = debug_backtrace();
28
- $caller = $trace[1];
29
-
30
- $suffix = sprintf(
31
- __( ' - %s%s() %s:%d', 'Q' )
32
- , isset($caller['class']) ? $caller['class'].'::' : ''
33
- , $caller['function']
34
- , isset( $caller['file'] ) ? $caller['file'] : 'n'
35
- , isset( $caller['line'] ) ? $caller['line'] : 'x'
36
- );
37
-
38
- if ( is_array( $log ) || is_object( $log ) ) {
39
- error_log( print_r( $log, true ).$suffix );
40
- } else {
41
- error_log( $log.$suffix );
42
- }
43
-
44
- }
45
-
46
- }
47
-
48
-
49
- }
1
+ <?php
2
+
3
+ // namespace ##
4
+ namespace q\eud\core;
5
+
6
+ /**
7
+ * helper Class
8
+ * @package q_eud\core
9
+ */
10
+ class helper extends \q_export_user_data {
11
+
12
+
13
+ /**
14
+ * Write to WP Error Log
15
+ *
16
+ * @since 1.5.0
17
+ * @return void
18
+ */
19
+ public static function log( $log )
20
+ {
21
+
22
+ if ( true === WP_DEBUG ) {
23
+
24
+ $trace = debug_backtrace();
25
+ $caller = $trace[1];
26
+
27
+ $suffix = sprintf(
28
+ __( ' - %s%s() %s:%d', 'Q' )
29
+ , isset($caller['class']) ? $caller['class'].'::' : ''
30
+ , $caller['function']
31
+ , isset( $caller['file'] ) ? $caller['file'] : 'n'
32
+ , isset( $caller['line'] ) ? $caller['line'] : 'x'
33
+ );
34
+
35
+ if ( is_array( $log ) || is_object( $log ) ) {
36
+ error_log( print_r( $log, true ).$suffix );
37
+ } else {
38
+ error_log( $log.$suffix );
39
+ }
40
+
41
+ }
42
+
43
+ }
44
+
45
+
46
+ }
 
 
 
library/core/user.php CHANGED
@@ -1,239 +1,258 @@
1
- <?php
2
-
3
- namespace q\report\core;
4
-
5
- use q\report\core\core as core;
6
- use q\report\core\helper as helper;
7
-
8
- // load it up ##
9
- \q\report\core\user::run();
10
-
11
- class user extends \q_export_user_data {
12
-
13
- public static function run()
14
- {
15
-
16
- if ( \is_admin() ) {
17
-
18
- // load user options ##
19
- \add_action( 'admin_init', array( get_class(), 'load' ), 1000002 );
20
-
21
- }
22
-
23
- }
24
-
25
-
26
- /**
27
- * Load up saved exports for this user
28
- * Set to public as hooked into action
29
- *
30
- * @since 0.9.6
31
- * @return Array of saved exports
32
- */
33
- public static function load()
34
- {
35
-
36
- return self::$q_report_exports =
37
- \get_user_meta( \get_current_user_id(), 'q_report_exports' ) ?
38
- \get_user_meta( \get_current_user_id(), 'q_report_exports', true ) :
39
- array() ;
40
-
41
- #self::log( $this->q_report_exports );
42
-
43
- }
44
-
45
-
46
-
47
- /**
48
- * Get list of saved exports for this user
49
- *
50
- * @since 0.9.4
51
- * @return Array of saved exports
52
- */
53
- public static function get_user_options()
54
- {
55
-
56
- // get the stored options - filter empty array items ##
57
- $q_report_exports = array_filter( self::$q_report_exports );
58
-
59
- // quick check if the array is empty ##
60
- if ( empty ( $q_report_exports ) ) {
61
-
62
- return false;
63
-
64
- }
65
-
66
- // test the array of saved exports ##
67
- #$this->pr( $q_report_exports );
68
-
69
- // start with an empty array ##
70
- $exports = array();
71
-
72
- // loop over each saved export and grab each key ##
73
- foreach ( $q_report_exports as $key => $value ) {
74
-
75
- $exports[] = $key;
76
-
77
- }
78
-
79
- // kick back array ##
80
- return $exports;
81
-
82
- }
83
-
84
-
85
- /**
86
- * Check for and load stored user options
87
- *
88
- * @since 0.9.3
89
- * @return void
90
- */
91
- public static function get_user_options_by_export( $export = null )
92
- {
93
-
94
- // sanity check ##
95
- if ( is_null ( $export ) ) { return false; }
96
-
97
- if ( isset( self::$q_report_exports[$export] ) ) {
98
-
99
- self::$usermeta_saved_fields = self::$q_report_exports[$export]['usermeta_saved_fields'];
100
- self::$bp_fields_saved_fields = self::$q_report_exports[$export]['bp_fields_saved_fields'];
101
- self::$bp_fields_update_time_saved_fields = self::$q_report_exports[$export]['bp_fields_update_time_saved_fields'];
102
- self::$updated_since_date = isset( self::$q_report_exports[$export]['updated_since_date'] ) ? self::$q_report_exports[$export]['updated_since_date'] : null ;
103
- self::$field_updated_since = isset( self::$q_report_exports[$export]['field_updated_since'] ) ? self::$q_report_exports[$export]['field_updated_since'] : null ;
104
- self::$role = self::$q_report_exports[$export]['role'];
105
- self::$roles = self::$q_report_exports[$export]['roles'];
106
- self::$groups = self::$q_report_exports[$export]['groups'];
107
- self::$user_fields = isset( self::$q_report_exports[$export]['user_fields'] ) ? self::$q_report_exports[$export]['user_fields'] : null ;
108
- self::$start_date = self::$q_report_exports[$export]['start_date'];
109
- self::$end_date = self::$q_report_exports[$export]['end_date'];
110
- self::$limit_offset = self::$q_report_exports[$export]['limit_offset'];
111
- self::$limit_total = self::$q_report_exports[$export]['limit_total'];
112
- self::$format = self::$q_report_exports[$export]['format'];
113
-
114
- } else {
115
-
116
- self::$usermeta_saved_fields = array();
117
- self::$bp_fields_saved_fields = array();
118
- self::$bp_fields_update_time_saved_fields = array();
119
- self::$updated_since_date = '';
120
- self::$field_updated_since = '';
121
- self::$role = '';
122
- self::$user_fields = '1';
123
- self::$roles = '1';
124
- self::$groups = '1';
125
- self::$start_date = '';
126
- self::$end_date = '';
127
- self::$limit_offset = '';
128
- self::$limit_total = '';
129
- self::$format = '';
130
-
131
- }
132
-
133
- }
134
-
135
-
136
- /**
137
- * Method to store user options
138
- *
139
- * @param string $save_export Export Key name
140
- * @param array $save_options Array of export options to save
141
- * @since 0.9.3
142
- * @return void
143
- */
144
- public static function set_user_options( $key = null, $options = null )
145
- {
146
-
147
- // sanity check ##
148
- if ( is_null ( $key ) || is_null ( $options ) ) {
149
-
150
- #$this->pr( 'missing save values' );
151
- return false;
152
-
153
- }
154
-
155
- #$this->pr( $key );
156
- #$this->pr( $options );
157
-
158
- // for now, I'm simply allowing keys to be resaved - but this is not so logical ##
159
- if ( array_key_exists( $key, self::$q_report_exports ) ) {
160
-
161
- #$this->pr( 'key exists, skipping save' );
162
- #return false;
163
-
164
- }
165
-
166
- if ( isset( $options ) && is_array( $options ) ) {
167
-
168
- // update_option sanitizes the option name but not the option value ##
169
- foreach ( $options as $field_name => $field_value ) {
170
-
171
- // so do that here. ##
172
- if ( is_array( $field_value ) ) {
173
-
174
- foreach ( $field_value as $field_array_key => $field_array_value ) {
175
-
176
- $options[$field_name][$field_array_key] = \sanitize_text_field( $field_array_value );
177
-
178
- }
179
-
180
- } else {
181
-
182
- $options[$field_name] = \sanitize_text_field( $field_value );
183
-
184
- }
185
-
186
- }
187
-
188
- // assign the sanitized array of values to the class property $q_report_exports as a new array with key $key ##
189
- self::$q_report_exports[$key] = $options;
190
-
191
- // update stored user_meta values, if previous key found ##
192
- if ( \get_user_meta( \get_current_user_id(), 'q_report_exports' ) !== false ) {
193
-
194
- #update_option( 'q_report_exports', $this->q_report_exports );
195
- \update_user_meta( \get_current_user_id(), 'q_report_exports', self::$q_report_exports );
196
-
197
- // create new user meta key ##
198
- } else {
199
-
200
- #add_option( 'q_report_exports', $this->q_report_exports, $deprecated, $autoload );
201
- \add_user_meta( \get_current_user_id(), 'q_report_exports', self::$q_report_exports );
202
-
203
- }
204
-
205
- }
206
-
207
- }
208
-
209
-
210
- /**
211
- * method to delete user options
212
- *
213
- * @param $key String Key name to drop from property
214
- * @since 0.9.3
215
- * @return void
216
- */
217
- public static function delete_user_options( $key = null )
218
- {
219
-
220
- // sanity check ##
221
- if ( is_null ( $key ) || ! array_key_exists( $key, self::$q_report_exports ) ) { return false; }
222
-
223
- // clean it up ##
224
- $key = \sanitize_text_field( $key );
225
-
226
- // check it out ##
227
- #$this->pr( $key );
228
-
229
- // drop the array by it's key name from the class property ##
230
- unset( self::$q_report_exports[$key] );
231
-
232
- // update the saved data ##
233
- \update_user_meta( \get_current_user_id(), 'q_report_exports', self::$q_report_exports );
234
-
235
- }
236
-
237
-
238
-
239
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace q\eud\core;
4
+
5
+ use q\eud\core\core as core;
6
+ use q\eud\core\helper as helper;
7
+
8
+ // load it up ##
9
+ \q\eud\core\user::run();
10
+
11
+ class user extends \q_export_user_data {
12
+
13
+ public static function run()
14
+ {
15
+
16
+ if ( \is_admin() ) {
17
+
18
+ // load user options ##
19
+ \add_action( 'admin_init', array( get_class(), 'load' ), 1000002 );
20
+
21
+ }
22
+
23
+ }
24
+
25
+
26
+ /**
27
+ * Load up saved exports for this user
28
+ * Set to public as hooked into action
29
+ *
30
+ * @since 0.9.6
31
+ * @return Array of saved exports
32
+ */
33
+ public static function load()
34
+ {
35
+
36
+ // convert outdated stored meta from q_report to q_eud_exports ##
37
+ if(
38
+ \get_user_meta( \get_current_user_id(), 'q_report', true )
39
+ && ! \get_user_meta( \get_current_user_id(), 'q_eud_exports' )
40
+ ){
41
+
42
+ // get old data ##
43
+ $old_data = \get_user_meta( \get_current_user_id(), 'q_report', true );
44
+
45
+ // add to user meta, as they do not have any stored values ##
46
+ \add_user_meta( \get_current_user_id(), 'q_eud_exports', $old_data );
47
+
48
+ // delete old data ---? perhaps better to leave it, even if it redundant?
49
+ // \delete_user_meta( \get_current_user_id(), 'q_eud_exports' );
50
+
51
+ }
52
+
53
+ // test #
54
+ // helper::log( \get_user_meta( \get_current_user_id(), 'q_eud_exports', true ) );
55
+
56
+ return self::$q_eud_exports =
57
+ \get_user_meta( \get_current_user_id(), 'q_eud_exports' ) ?
58
+ \get_user_meta( \get_current_user_id(), 'q_eud_exports', true ) :
59
+ array() ;
60
+
61
+ }
62
+
63
+
64
+
65
+
66
+ /**
67
+ * Get list of saved exports for this user
68
+ *
69
+ * @since 0.9.4
70
+ * @return Array of saved exports
71
+ */
72
+ public static function get_user_options()
73
+ {
74
+
75
+ // get the stored options - filter empty array items ##
76
+ $q_eud_exports = array_filter( self::$q_eud_exports );
77
+
78
+ // quick check if the array is empty ##
79
+ if ( empty ( $q_eud_exports ) ) {
80
+
81
+ return false;
82
+
83
+ }
84
+
85
+ // test the array of saved exports ##
86
+ #$this->pr( $q_eud_exports );
87
+
88
+ // start with an empty array ##
89
+ $exports = array();
90
+
91
+ // loop over each saved export and grab each key ##
92
+ foreach ( $q_eud_exports as $key => $value ) {
93
+
94
+ $exports[] = $key;
95
+
96
+ }
97
+
98
+ // kick back array ##
99
+ return $exports;
100
+
101
+ }
102
+
103
+
104
+ /**
105
+ * Check for and load stored user options
106
+ *
107
+ * @since 0.9.3
108
+ * @return void
109
+ */
110
+ public static function get_user_options_by_export( $export = null )
111
+ {
112
+
113
+ // sanity check ##
114
+ if ( is_null ( $export ) ) { return false; }
115
+
116
+ if ( isset( self::$q_eud_exports[$export] ) ) {
117
+
118
+ self::$usermeta_saved_fields = self::$q_eud_exports[$export]['usermeta_saved_fields'];
119
+ self::$bp_fields_saved_fields = self::$q_eud_exports[$export]['bp_fields_saved_fields'];
120
+ self::$bp_fields_update_time_saved_fields = self::$q_eud_exports[$export]['bp_fields_update_time_saved_fields'];
121
+ self::$updated_since_date = isset( self::$q_eud_exports[$export]['updated_since_date'] ) ? self::$q_eud_exports[$export]['updated_since_date'] : null ;
122
+ self::$field_updated_since = isset( self::$q_eud_exports[$export]['field_updated_since'] ) ? self::$q_eud_exports[$export]['field_updated_since'] : null ;
123
+ self::$role = self::$q_eud_exports[$export]['role'];
124
+ self::$roles = self::$q_eud_exports[$export]['roles'];
125
+ self::$groups = self::$q_eud_exports[$export]['groups'];
126
+ self::$user_fields = isset( self::$q_eud_exports[$export]['user_fields'] ) ? self::$q_eud_exports[$export]['user_fields'] : null ;
127
+ self::$start_date = self::$q_eud_exports[$export]['start_date'];
128
+ self::$end_date = self::$q_eud_exports[$export]['end_date'];
129
+ self::$limit_offset = self::$q_eud_exports[$export]['limit_offset'];
130
+ self::$limit_total = self::$q_eud_exports[$export]['limit_total'];
131
+ self::$format = self::$q_eud_exports[$export]['format'];
132
+
133
+ } else {
134
+
135
+ self::$usermeta_saved_fields = array();
136
+ self::$bp_fields_saved_fields = array();
137
+ self::$bp_fields_update_time_saved_fields = array();
138
+ self::$updated_since_date = '';
139
+ self::$field_updated_since = '';
140
+ self::$role = '';
141
+ self::$user_fields = '1';
142
+ self::$roles = '1';
143
+ self::$groups = '1';
144
+ self::$start_date = '';
145
+ self::$end_date = '';
146
+ self::$limit_offset = '';
147
+ self::$limit_total = '';
148
+ self::$format = '';
149
+
150
+ }
151
+
152
+ }
153
+
154
+
155
+ /**
156
+ * Method to store user options
157
+ *
158
+ * @param string $save_export Export Key name
159
+ * @param array $save_options Array of export options to save
160
+ * @since 0.9.3
161
+ * @return void
162
+ */
163
+ public static function set_user_options( $key = null, $options = null )
164
+ {
165
+
166
+ // sanity check ##
167
+ if ( is_null ( $key ) || is_null ( $options ) ) {
168
+
169
+ #$this->pr( 'missing save values' );
170
+ return false;
171
+
172
+ }
173
+
174
+ #$this->pr( $key );
175
+ #$this->pr( $options );
176
+
177
+ // for now, I'm simply allowing keys to be resaved - but this is not so logical ##
178
+ if ( array_key_exists( $key, self::$q_eud_exports ) ) {
179
+
180
+ #$this->pr( 'key exists, skipping save' );
181
+ #return false;
182
+
183
+ }
184
+
185
+ if ( isset( $options ) && is_array( $options ) ) {
186
+
187
+ // update_option sanitizes the option name but not the option value ##
188
+ foreach ( $options as $field_name => $field_value ) {
189
+
190
+ // so do that here. ##
191
+ if ( is_array( $field_value ) ) {
192
+
193
+ foreach ( $field_value as $field_array_key => $field_array_value ) {
194
+
195
+ $options[$field_name][$field_array_key] = \sanitize_text_field( $field_array_value );
196
+
197
+ }
198
+
199
+ } else {
200
+
201
+ $options[$field_name] = \sanitize_text_field( $field_value );
202
+
203
+ }
204
+
205
+ }
206
+
207
+ // assign the sanitized array of values to the class property $q_eud_exports as a new array with key $key ##
208
+ self::$q_eud_exports[$key] = $options;
209
+
210
+ // update stored user_meta values, if previous key found ##
211
+ if ( \get_user_meta( \get_current_user_id(), 'q_eud_exports' ) !== false ) {
212
+
213
+ #update_option( 'q_eud_exports', $this->q_eud_exports );
214
+ \update_user_meta( \get_current_user_id(), 'q_eud_exports', self::$q_eud_exports );
215
+
216
+ // create new user meta key ##
217
+ } else {
218
+
219
+ #add_option( 'q_eud_exports', $this->q_eud_exports, $deprecated, $autoload );
220
+ \add_user_meta( \get_current_user_id(), 'q_eud_exports', self::$q_eud_exports );
221
+
222
+ }
223
+
224
+ }
225
+
226
+ }
227
+
228
+
229
+ /**
230
+ * method to delete user options
231
+ *
232
+ * @param $key String Key name to drop from property
233
+ * @since 0.9.3
234
+ * @return void
235
+ */
236
+ public static function delete_user_options( $key = null )
237
+ {
238
+
239
+ // sanity check ##
240
+ if ( is_null ( $key ) || ! array_key_exists( $key, self::$q_eud_exports ) ) { return false; }
241
+
242
+ // clean it up ##
243
+ $key = \sanitize_text_field( $key );
244
+
245
+ // check it out ##
246
+ #$this->pr( $key );
247
+
248
+ // drop the array by it's key name from the class property ##
249
+ unset( self::$q_eud_exports[$key] );
250
+
251
+ // update the saved data ##
252
+ \update_user_meta( \get_current_user_id(), 'q_eud_exports', self::$q_eud_exports );
253
+
254
+ }
255
+
256
+
257
+
258
+ }
library/core/xml.php DELETED
@@ -1,112 +0,0 @@
1
- <?php
2
-
3
- namespace q\report\core;
4
-
5
- use q\report\core\core as core;
6
- use q\report\core\helper as helper;
7
-
8
- /**
9
- * XML template for excel file format
10
- *
11
- * @since 0.7.7
12
- **/
13
-
14
- // load it up ##
15
- #\q\report\core\core::run();
16
-
17
- class xml extends \q_export_user_data {
18
-
19
- public static function begin()
20
- {
21
-
22
- /*
23
- $xml_string = <<<XML
24
- <xml version="1.0">
25
- <mso-application progid="Excel.Sheet">
26
- <Workbook
27
- xmlns="urn:schemas-microsoft-com:office:spreadsheet"
28
- xmlns:o="urn:schemas-microsoft-com:office:office"
29
- xmlns:x="urn:schemas-microsoft-com:office:excel"
30
- xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
31
- xmlns:html="http://www.w3.org/TR/REC-html40">
32
- <Worksheet ss:Name="Exported Users">
33
- <Table>
34
- XML;
35
- $xml_object = new \SimpleXMLElement($xml_string);
36
- return $xml_object->asXML();
37
- #Changed by Benny to PHP XML syntax to clear 500
38
- */
39
- $xml_doc_begin =
40
- '<?xml version="1.0"?>
41
- <?mso-application progid="Excel.Sheet"?>
42
- <Workbook
43
- xmlns="urn:schemas-microsoft-com:office:spreadsheet"
44
- xmlns:o="urn:schemas-microsoft-com:office:office"
45
- xmlns:x="urn:schemas-microsoft-com:office:excel"
46
- xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
47
- xmlns:html="http://www.w3.org/TR/REC-html40">
48
- <Worksheet ss:Name="Exported Users">
49
- <Table>';
50
-
51
- return $xml_doc_begin;
52
-
53
- }
54
-
55
-
56
-
57
-
58
- public static function pre()
59
- {
60
-
61
- $xml_pre =
62
- '<Row>
63
- <Cell>
64
- <Data ss:Type="String">';
65
-
66
- return $xml_pre;
67
-
68
- }
69
-
70
-
71
-
72
- public static function seperator()
73
- {
74
-
75
- $xml_seperator =
76
- '</Data>
77
- </Cell>
78
- <Cell>
79
- <Data ss:Type="String">';
80
-
81
- return $xml_seperator;
82
-
83
- }
84
-
85
-
86
-
87
- public static function breaker()
88
- {
89
-
90
- $xml_breaker =
91
- '</Data>
92
- </Cell>
93
- </Row>';
94
-
95
- return $xml_breaker;
96
-
97
- }
98
-
99
-
100
- public static function end()
101
- {
102
-
103
- $xml_doc_end = '
104
- </Table>
105
- </Worksheet>
106
- </Workbook>';
107
-
108
- return $xml_doc_end;
109
-
110
- }
111
-
112
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
package-lock.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ {
2
+ "name": "export-user-data",
3
+ "version": "2.1.0",
4
+ "lockfileVersion": 1,
5
+ "requires": true
6
+ }
package.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "export-user-data",
3
+ "version": "2.1.0",
4
+ "description": "Q Plugins ~ Export User data and metadata",
5
+ "author": "Q Studio",
6
+ "homepage": "https://qstudio.us",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "qstudio/export-user-data"
10
+ },
11
+ "license": "GPL-3.0-or-later",
12
+ }
readme.md CHANGED
@@ -1,23 +1,26 @@
1
- # Export User Data #
2
-
3
- **Contributors:** qlstudio
4
- **Tags:** user, users, xprofile, usermeta csv, excel, batch, export, save, download
5
- **Requires at least:** 5.0.0
6
- **Tested up to:** 5.0.0
7
- **Stable tag:** 2.0.3
8
- **License:** GPLv2
9
-
10
- Export users data and metadata to a csv or Excel file
11
-
12
- ## Description ##
13
-
14
- A plugin that exports WordPress user data and metadata.
15
-
16
- Includes an option to export the users by role, registration date range, usermeta option and two export formats.
17
-
18
- ### Features ###
19
-
20
- * Exports all users fields
21
- * Exports users meta
22
- * Exports users by role
23
- * Exports users by date range
 
 
 
1
+ # Export User Data #
2
+
3
+ **Contributors:** qlstudio
4
+ **Tags:** user, users, xprofile, usermeta csv, excel, batch, export, save, download
5
+ **Requires PHP:** 6.0
6
+ **Requires at least:** 5.0
7
+ **Tested up to:** 5.5
8
+ **Stable tag:** 2.1.0
9
+ **License:** GPLv2
10
+
11
+ Export users data and metadata to a csv or Excel file
12
+
13
+ ## Description ##
14
+
15
+ A plugin that exports WordPress user data and metadata.
16
+
17
+ Includes an option to export the users by role, registration date range, usermeta option and two export formats.
18
+
19
+ This plugin is designed to export user data stored in the 2 standard WordPress user data tables wp_users and wp_usermeta, if you use a plugin which stores data in its own database tables, this plugin will not export this data, without customization.
20
+
21
+ ### Features ###
22
+
23
+ * Exports all standard users fields
24
+ * Exports users meta
25
+ * Exports users by role
26
+ * Exports users by date range
readme.txt CHANGED
@@ -1,9 +1,200 @@
1
- === Export User Data ===
2
- Contributors: qlstudio
3
- Tags: user, users, xprofile, usermeta csv, excel, batch, export, save, download
4
- Requires at least: 4.8.0
5
- Tested up to: 5.0.0
6
- Stable tag: 2.0.3
7
- License: GPLv2
8
-
9
- Export users data and metadata to a csv or Excel fil
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Export User Data ===
2
+ Contributors: qlstudio
3
+ Tags: user, users, xprofile, usermeta csv, excel, batch, export, save, download
4
+ Requires PHP: 6.0
5
+ Requires at least: 4.8
6
+ Tested up to: 5.5
7
+ Stable tag: 2.1.0
8
+ License: GPLv2
9
+
10
+ Export users data and metadata to a csv or Excel file
11
+
12
+ === Description ===
13
+
14
+ A plugin that exports WordPress user data and metadata.
15
+
16
+ Includes an option to export the users by role, registration date range, usermeta option and two export formats.
17
+
18
+ This plugin is designed to export user data stored in the 2 standard WordPress user data tables wp_users and wp_usermeta, if you use a plugin which stores data in its own database tables, this plugin will not export this data, without customization.
19
+
20
+ == Features ==
21
+
22
+ * Exports all standard users fields
23
+ * Exports users meta
24
+ * Exports users by role
25
+ * Exports users by date range
26
+
27
+ == Screenshots ==
28
+
29
+ 1. Example of Admin Export View
30
+
31
+ == Changelog ==
32
+
33
+ = 2.1.0 =
34
+
35
+ * Excel 2007 export option added - thanks to @reyneke-vosz - https://github.com/qstudio/export-user-data/pull/5
36
+ * Excell 2003 export option removed, as no suitable open-source library available
37
+ * Validated as working in WP 5.5.0
38
+ * BuddyPress support removed... sorry, but this plugin now only supports exporting data from native WordPress tables
39
+
40
+ = 2.0.3 =
41
+
42
+ * Removed remote call to jQuery UI CSS
43
+ * Added extra sanitization to $_POST data
44
+ * Made main class name "more" unique
45
+
46
+ = 2.0.2 =
47
+
48
+ * Cleanup and tagging for WP Repo
49
+
50
+ = 2.0.1 =
51
+
52
+ * Deprecated BuddyPress support as untested in 4 years
53
+
54
+ = 2.0.0 =
55
+
56
+ * Fork to new name Q Report
57
+ * namespaced and moved to standard Q plugin setup model
58
+ * buddypress support might be flaky due to limited testing
59
+
60
+ = 1.3.1 =
61
+
62
+ * Moved all internal action hooks to admin_init to allow for internal function loading
63
+
64
+ = 1.3.0 =
65
+
66
+ * Added extra data sanitization before outputting to file - thanks to Hely Shah <helyhshah@gmail.com> for te heads-up
67
+
68
+ = 1.2.8 =
69
+
70
+ * New: Added load_buddypress() methods to test for buddypress and load up if missing
71
+ * New: move action hooks and priority to load later
72
+ * New: Plugin no longer uses singleton model to instatiate - instead called from action hook to public function
73
+ * New: added log() to debug.log file to help debugging issues
74
+ * Update: jQuery datepickers pull start_of_week value from WordPress
75
+ * Tested on 4.4.2
76
+
77
+ = 1.2.7 =
78
+
79
+ * Added: Spanish translation - thanks Elías Gómez Sainz ( elias@estudions.es )
80
+
81
+ = 1.2.6 =
82
+ * Update: WP 4.4.1
83
+
84
+ = 1.2.3 =
85
+ * Fix: to remove minor security loop hole
86
+ * New: Added option to remove standard wp_users data from export
87
+ * Fix: removed roles and groups columns from export when options hidden
88
+
89
+ = 1.2.2 =
90
+ * Minor FIxes
91
+
92
+ = 1.2.1 =
93
+ * Checked on WP 4.3.1
94
+ * Moved text-domain to string in preperation for addition to translate.wordpress.org
95
+ * Added Log() method to allow for debugging to WP Error Log
96
+ * Added Greek translation - Thanks @Leonidas Mi
97
+ * Added option to limit export by last_updated date of specific xprofile field - Thanks to @cwjordan
98
+
99
+ = 1.2.0 =
100
+ * Data stored in recursive and serialized arrays is now exported in a flat string format with safe delimiters ( ||, ||| - etc. )
101
+
102
+ = 1.1.1 =
103
+ * Removed accidently included .git files
104
+
105
+ = 1.1.0 =
106
+ * Version change to sync SVN on wordpress.org
107
+
108
+ = 1.0.4 =
109
+ * Added unserialize function with @ fallback
110
+ * Removed anonymous function to allow support for PHP < 5.2
111
+
112
+ = 1.0.3 =
113
+ * Tested as working on WordPress 4.1.0.
114
+
115
+ = 1.0.2 =
116
+ * Removed get_user_meta method, as not effective.
117
+ * Added registration date from and to pickers - to replace monthly <select> lists.
118
+
119
+ = 1.0.1 =
120
+ * Added recursive_implode() method to flatten data stored in arrays ( exported with keys and values divided by "|" )
121
+
122
+ = 1.0.0 =
123
+ * Reduced all get_user_meta queries to a single call to improve performance
124
+ * Serialized data is now returned in it's pure stored format - not imploded or unserialized to avoid data structure loss
125
+
126
+ = 0.9.9 =
127
+ * get_uermeta renamed get_user_meta to be more consistent with WP
128
+ * get_user_meta tidied up and tested on larger exports
129
+ * added option to export user BP Groups
130
+ * added option to export all user WP Roles
131
+
132
+ = 0.9.8 =
133
+ * added get_usermeta() to check if meta keys are unique and return an array if not
134
+ * removed known_arrays() filter to allow for array data to be returned correctly - too hacky
135
+
136
+ = 0.9.7 =
137
+ * Added known_arrays() filter to allow for array data to be returned correctly
138
+
139
+ = 0.9.6 =
140
+ * Save, load and delete stored export settings - thanks to @cwjordan
141
+ * Overcome memory outages on large exports - thanks to @grexican
142
+ * Tested on WP 4.0.0 & BP 2.1.0
143
+
144
+ = 0.9.5 =
145
+ * BP Serialized data fixes - thanks to @nicmare & @grexican
146
+ * Tested on WP 3.9.2 & BP 2.0.2
147
+
148
+ = 0.9.4 =
149
+ * BP X Profile Export Fix ( > version 2.0 )
150
+
151
+ = 0.9.3 =
152
+ * fix for hidden admin bar
153
+
154
+ = 0.9.2 =
155
+ * removed $key assignment casting to integer
156
+
157
+ = 0.9.1 =
158
+ * Tested with WP 3.9
159
+ * Fix for BuddyPress 2.0 bug
160
+
161
+ = 0.9.0 =
162
+ * Moved plugin class to singleton model
163
+ * Improved language handling
164
+ * French translation - thanks @bastho - http://wordpress.org/support/profile/bastho
165
+
166
+ = 0.8.3 =
167
+ * clarified export limit options
168
+
169
+ = 0.8.2 =
170
+ * corrected buddypress export option - broken in 0.8.1
171
+ * changed get_users arguments, in attempt to reduce memory usage
172
+
173
+ = 0.8.1 =
174
+ * Added experimental range limiter for exports
175
+ * Extra input data sanitizing
176
+
177
+ = 0.8 =
178
+ * moved plugin instatiation to the WP hook: init
179
+ * moved bp calls outside export loop
180
+ * added extra isset calls on values in export loop to clean up error log not sets
181
+
182
+ = 0.7.8 =
183
+ * added xml template for Excel exports - thanks to phil@fixitlab.com :)
184
+
185
+ = 0.7.2 =
186
+ * fixes to allow exports without selecting extra user date from usermeta or x-profile
187
+
188
+ = 0.6.3 =
189
+ * added multiselect to pick usermeta and xprofile fields
190
+
191
+ = 0.5 =
192
+ * First public release.
193
+
194
+ == Upgrade Notice ==
195
+
196
+ = 0.6.3 =
197
+ Latest.
198
+
199
+ = 0.5 =
200
+ First release.
vendor/PHP_XLSXWriter/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
1
+ vendor
2
+ .idea
vendor/PHP_XLSXWriter/LICENSE ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Mark Jones
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
vendor/PHP_XLSXWriter/README.md ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ PHP_XLSXWriter
2
+ ==============
3
+
4
+ This library is designed to be lightweight, and have minimal memory usage.
5
+
6
+ It is designed to output an Excel compatible spreadsheet in (Office 2007+) xlsx format, with just basic features supported:
7
+ * supports PHP 5.2.1+
8
+ * takes UTF-8 encoded input
9
+ * multiple worksheets
10
+ * supports currency/date/numeric cell formatting, simple formulas
11
+ * supports basic cell styling
12
+ * supports writing huge 100K+ row spreadsheets
13
+
14
+ [Never run out of memory with PHPExcel again](https://github.com/mk-j/PHP_XLSXWriter).
15
+
16
+ Simple PHP CLI example:
17
+ ```php
18
+ $data = array(
19
+ array('year','month','amount'),
20
+ array('2003','1','220'),
21
+ array('2003','2','153.5'),
22
+ );
23
+
24
+ $writer = new XLSXWriter();
25
+ $writer->writeSheet($data);
26
+ $writer->writeToFile('output.xlsx');
27
+ ```
28
+
29
+ Simple/Advanced Cell Formats:
30
+ ```php
31
+ $header = array(
32
+ 'created'=>'date',
33
+ 'product_id'=>'integer',
34
+ 'quantity'=>'#,##0',
35
+ 'amount'=>'price',
36
+ 'description'=>'string',
37
+ 'tax'=>'[$$-1009]#,##0.00;[RED]-[$$-1009]#,##0.00',
38
+ );
39
+ $data = array(
40
+ array('2015-01-01',873,1,'44.00','misc','=D2*0.05'),
41
+ array('2015-01-12',324,2,'88.00','none','=D3*0.05'),
42
+ );
43
+
44
+ $writer = new XLSXWriter();
45
+ $writer->writeSheetHeader('Sheet1', $header );
46
+ foreach($data as $row)
47
+ $writer->writeSheetRow('Sheet1', $row );
48
+ $writer->writeToFile('example.xlsx');
49
+ ```
50
+
51
+ 50000 rows: (1.4s, 0MB memory usage)
52
+ ```php
53
+ include_once("xlsxwriter.class.php");
54
+ $writer = new XLSXWriter();
55
+ $writer->writeSheetHeader('Sheet1', array('c1'=>'integer','c2'=>'integer','c3'=>'integer','c4'=>'integer') );
56
+ for($i=0; $i<50000; $i++)
57
+ {
58
+ $writer->writeSheetRow('Sheet1', array($i, $i+1, $i+2, $i+3) );
59
+ }
60
+ $writer->writeToFile('huge.xlsx');
61
+ echo '#'.floor((memory_get_peak_usage())/1024/1024)."MB"."\n";
62
+ ```
63
+ | rows | time | memory |
64
+ | ------ | ---- | ------ |
65
+ | 50000 | 1.4s | 0MB |
66
+ | 100000 | 2.7s | 0MB |
67
+ | 150000 | 4.1s | 0MB |
68
+ | 200000 | 5.7s | 0MB |
69
+ | 250000 | 7.0s | 0MB |
70
+
71
+ Simple cell formats map to more advanced cell formats
72
+
73
+ | simple formats | format code |
74
+ | ---------- | ---- |
75
+ | string | @ |
76
+ | integer | 0 |
77
+ | date | YYYY-MM-DD |
78
+ | datetime | YYYY-MM-DD HH:MM:SS |
79
+ | time | HH:MM:SS |
80
+ | price | #,##0.00 |
81
+ | dollar | [$$-1009]#,##0.00;[RED]-[$$-1009]#,##0.00 |
82
+ | euro | #,##0.00 [$€-407];[RED]-#,##0.00 [$€-407] |
83
+
84
+
85
+ Basic cell styles have been available since version 0.30
86
+
87
+ | style | allowed values |
88
+ | ------------ | ---- |
89
+ | font | Arial, Times New Roman, Courier New, Comic Sans MS |
90
+ | font-size | 8,9,10,11,12 ... |
91
+ | font-style | bold, italic, underline, strikethrough or multiple ie: 'bold,italic' |
92
+ | border | left, right, top, bottom, or multiple ie: 'top,left' |
93
+ | border-style | thin, medium, thick, dashDot, dashDotDot, dashed, dotted, double, hair, mediumDashDot, mediumDashDotDot, mediumDashed, slantDashDot |
94
+ | border-color | #RRGGBB, ie: #ff99cc or #f9c |
95
+ | color | #RRGGBB, ie: #ff99cc or #f9c |
96
+ | fill | #RRGGBB, ie: #eeffee or #efe |
97
+ | halign | general, left, right, justify, center |
98
+ | valign | bottom, center, distributed |
99
+
100
+
vendor/PHP_XLSXWriter/composer.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "mk-j/php_xlsxwriter",
3
+ "description": "PHP Library to write XLSX files",
4
+ "keywords": ["php", "library","xls", "xlsx", "excel"],
5
+ "type": "project",
6
+ "homepage": "https://github.com/mk-j/PHP_XLSXWriter",
7
+ "license": "MIT",
8
+
9
+ "autoload": {
10
+ "classmap": ["xlsxwriter.class.php"]
11
+ },
12
+ "require-dev": {
13
+ "phpunit/phpunit": "4.3.*"
14
+ },
15
+ "require": {
16
+ "php": ">=5.2.1",
17
+ "ext-zip": "*"
18
+ }
19
+ }
vendor/PHP_XLSXWriter/composer.lock ADDED
@@ -0,0 +1,760 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_readme": [
3
+ "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
+ "This file is @generated automatically"
6
+ ],
7
+ "hash": "89c1f54283c6b465c6b1a751a5270d78",
8
+ "packages": [],
9
+ "packages-dev": [
10
+ {
11
+ "name": "doctrine/instantiator",
12
+ "version": "1.0.4",
13
+ "source": {
14
+ "type": "git",
15
+ "url": "https://github.com/doctrine/instantiator.git",
16
+ "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119"
17
+ },
18
+ "dist": {
19
+ "type": "zip",
20
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119",
21
+ "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119",
22
+ "shasum": ""
23
+ },
24
+ "require": {
25
+ "php": ">=5.3,<8.0-DEV"
26
+ },
27
+ "require-dev": {
28
+ "athletic/athletic": "~0.1.8",
29
+ "ext-pdo": "*",
30
+ "ext-phar": "*",
31
+ "phpunit/phpunit": "~4.0",
32
+ "squizlabs/php_codesniffer": "2.0.*@ALPHA"
33
+ },
34
+ "type": "library",
35
+ "extra": {
36
+ "branch-alias": {
37
+ "dev-master": "1.0.x-dev"
38
+ }
39
+ },
40
+ "autoload": {
41
+ "psr-0": {
42
+ "Doctrine\\Instantiator\\": "src"
43
+ }
44
+ },
45
+ "notification-url": "https://packagist.org/downloads/",
46
+ "license": [
47
+ "MIT"
48
+ ],
49
+ "authors": [
50
+ {
51
+ "name": "Marco Pivetta",
52
+ "email": "ocramius@gmail.com",
53
+ "homepage": "http://ocramius.github.com/"
54
+ }
55
+ ],
56
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
57
+ "homepage": "https://github.com/doctrine/instantiator",
58
+ "keywords": [
59
+ "constructor",
60
+ "instantiate"
61
+ ],
62
+ "time": "2014-10-13 12:58:55"
63
+ },
64
+ {
65
+ "name": "phpunit/php-code-coverage",
66
+ "version": "2.0.11",
67
+ "source": {
68
+ "type": "git",
69
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
70
+ "reference": "53603b3c995f5aab6b59c8e08c3a663d2cc810b7"
71
+ },
72
+ "dist": {
73
+ "type": "zip",
74
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/53603b3c995f5aab6b59c8e08c3a663d2cc810b7",
75
+ "reference": "53603b3c995f5aab6b59c8e08c3a663d2cc810b7",
76
+ "shasum": ""
77
+ },
78
+ "require": {
79
+ "php": ">=5.3.3",
80
+ "phpunit/php-file-iterator": "~1.3",
81
+ "phpunit/php-text-template": "~1.2",
82
+ "phpunit/php-token-stream": "~1.3",
83
+ "sebastian/environment": "~1.0",
84
+ "sebastian/version": "~1.0"
85
+ },
86
+ "require-dev": {
87
+ "ext-xdebug": ">=2.1.4",
88
+ "phpunit/phpunit": "~4.1"
89
+ },
90
+ "suggest": {
91
+ "ext-dom": "*",
92
+ "ext-xdebug": ">=2.2.1",
93
+ "ext-xmlwriter": "*"
94
+ },
95
+ "type": "library",
96
+ "extra": {
97
+ "branch-alias": {
98
+ "dev-master": "2.0.x-dev"
99
+ }
100
+ },
101
+ "autoload": {
102
+ "classmap": [
103
+ "src/"
104
+ ]
105
+ },
106
+ "notification-url": "https://packagist.org/downloads/",
107
+ "include-path": [
108
+ ""
109
+ ],
110
+ "license": [
111
+ "BSD-3-Clause"
112
+ ],
113
+ "authors": [
114
+ {
115
+ "name": "Sebastian Bergmann",
116
+ "email": "sb@sebastian-bergmann.de",
117
+ "role": "lead"
118
+ }
119
+ ],
120
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
121
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
122
+ "keywords": [
123
+ "coverage",
124
+ "testing",
125
+ "xunit"
126
+ ],
127
+ "time": "2014-08-31 06:33:04"
128
+ },
129
+ {
130
+ "name": "phpunit/php-file-iterator",
131
+ "version": "1.3.4",
132
+ "source": {
133
+ "type": "git",
134
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
135
+ "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
136
+ },
137
+ "dist": {
138
+ "type": "zip",
139
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
140
+ "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
141
+ "shasum": ""
142
+ },
143
+ "require": {
144
+ "php": ">=5.3.3"
145
+ },
146
+ "type": "library",
147
+ "autoload": {
148
+ "classmap": [
149
+ "File/"
150
+ ]
151
+ },
152
+ "notification-url": "https://packagist.org/downloads/",
153
+ "include-path": [
154
+ ""
155
+ ],
156
+ "license": [
157
+ "BSD-3-Clause"
158
+ ],
159
+ "authors": [
160
+ {
161
+ "name": "Sebastian Bergmann",
162
+ "email": "sb@sebastian-bergmann.de",
163
+ "role": "lead"
164
+ }
165
+ ],
166
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
167
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
168
+ "keywords": [
169
+ "filesystem",
170
+ "iterator"
171
+ ],
172
+ "time": "2013-10-10 15:34:57"
173
+ },
174
+ {
175
+ "name": "phpunit/php-text-template",
176
+ "version": "1.2.0",
177
+ "source": {
178
+ "type": "git",
179
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
180
+ "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
181
+ },
182
+ "dist": {
183
+ "type": "zip",
184
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
185
+ "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
186
+ "shasum": ""
187
+ },
188
+ "require": {
189
+ "php": ">=5.3.3"
190
+ },
191
+ "type": "library",
192
+ "autoload": {
193
+ "classmap": [
194
+ "Text/"
195
+ ]
196
+ },
197
+ "notification-url": "https://packagist.org/downloads/",
198
+ "include-path": [
199
+ ""
200
+ ],
201
+ "license": [
202
+ "BSD-3-Clause"
203
+ ],
204
+ "authors": [
205
+ {
206
+ "name": "Sebastian Bergmann",
207
+ "email": "sb@sebastian-bergmann.de",
208
+ "role": "lead"
209
+ }
210
+ ],
211
+ "description": "Simple template engine.",
212
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
213
+ "keywords": [
214
+ "template"
215
+ ],
216
+ "time": "2014-01-30 17:20:04"
217
+ },
218
+ {
219
+ "name": "phpunit/php-timer",
220
+ "version": "1.0.5",
221
+ "source": {
222
+ "type": "git",
223
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
224
+ "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c"
225
+ },
226
+ "dist": {
227
+ "type": "zip",
228
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
229
+ "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
230
+ "shasum": ""
231
+ },
232
+ "require": {
233
+ "php": ">=5.3.3"
234
+ },
235
+ "type": "library",
236
+ "autoload": {
237
+ "classmap": [
238
+ "PHP/"
239
+ ]
240
+ },
241
+ "notification-url": "https://packagist.org/downloads/",
242
+ "include-path": [
243
+ ""
244
+ ],
245
+ "license": [
246
+ "BSD-3-Clause"
247
+ ],
248
+ "authors": [
249
+ {
250
+ "name": "Sebastian Bergmann",
251
+ "email": "sb@sebastian-bergmann.de",
252
+ "role": "lead"
253
+ }
254
+ ],
255
+ "description": "Utility class for timing",
256
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
257
+ "keywords": [
258
+ "timer"
259
+ ],
260
+ "time": "2013-08-02 07:42:54"
261
+ },
262
+ {
263
+ "name": "phpunit/php-token-stream",
264
+ "version": "1.3.0",
265
+ "source": {
266
+ "type": "git",
267
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
268
+ "reference": "f8d5d08c56de5cfd592b3340424a81733259a876"
269
+ },
270
+ "dist": {
271
+ "type": "zip",
272
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/f8d5d08c56de5cfd592b3340424a81733259a876",
273
+ "reference": "f8d5d08c56de5cfd592b3340424a81733259a876",
274
+ "shasum": ""
275
+ },
276
+ "require": {
277
+ "ext-tokenizer": "*",
278
+ "php": ">=5.3.3"
279
+ },
280
+ "require-dev": {
281
+ "phpunit/phpunit": "~4.2"
282
+ },
283
+ "type": "library",
284
+ "extra": {
285
+ "branch-alias": {
286
+ "dev-master": "1.3-dev"
287
+ }
288
+ },
289
+ "autoload": {
290
+ "classmap": [
291
+ "src/"
292
+ ]
293
+ },
294
+ "notification-url": "https://packagist.org/downloads/",
295
+ "license": [
296
+ "BSD-3-Clause"
297
+ ],
298
+ "authors": [
299
+ {
300
+ "name": "Sebastian Bergmann",
301
+ "email": "sebastian@phpunit.de"
302
+ }
303
+ ],
304
+ "description": "Wrapper around PHP's tokenizer extension.",
305
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
306
+ "keywords": [
307
+ "tokenizer"
308
+ ],
309
+ "time": "2014-08-31 06:12:13"
310
+ },
311
+ {
312
+ "name": "phpunit/phpunit",
313
+ "version": "4.3.5",
314
+ "source": {
315
+ "type": "git",
316
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
317
+ "reference": "2dab9d593997db4abcf58d0daf798eb4e9cecfe1"
318
+ },
319
+ "dist": {
320
+ "type": "zip",
321
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2dab9d593997db4abcf58d0daf798eb4e9cecfe1",
322
+ "reference": "2dab9d593997db4abcf58d0daf798eb4e9cecfe1",
323
+ "shasum": ""
324
+ },
325
+ "require": {
326
+ "ext-dom": "*",
327
+ "ext-json": "*",
328
+ "ext-pcre": "*",
329
+ "ext-reflection": "*",
330
+ "ext-spl": "*",
331
+ "php": ">=5.3.3",
332
+ "phpunit/php-code-coverage": "~2.0",
333
+ "phpunit/php-file-iterator": "~1.3.2",
334
+ "phpunit/php-text-template": "~1.2",
335
+ "phpunit/php-timer": "~1.0.2",
336
+ "phpunit/phpunit-mock-objects": "~2.3",
337
+ "sebastian/comparator": "~1.0",
338
+ "sebastian/diff": "~1.1",
339
+ "sebastian/environment": "~1.0",
340
+ "sebastian/exporter": "~1.0",
341
+ "sebastian/version": "~1.0",
342
+ "symfony/yaml": "~2.0"
343
+ },
344
+ "suggest": {
345
+ "phpunit/php-invoker": "~1.1"
346
+ },
347
+ "bin": [
348
+ "phpunit"
349
+ ],
350
+ "type": "library",
351
+ "extra": {
352
+ "branch-alias": {
353
+ "dev-master": "4.3.x-dev"
354
+ }
355
+ },
356
+ "autoload": {
357
+ "classmap": [
358
+ "src/"
359
+ ]
360
+ },
361
+ "notification-url": "https://packagist.org/downloads/",
362
+ "include-path": [
363
+ "",
364
+ "../../symfony/yaml/"
365
+ ],
366
+ "license": [
367
+ "BSD-3-Clause"
368
+ ],
369
+ "authors": [
370
+ {
371
+ "name": "Sebastian Bergmann",
372
+ "email": "sebastian@phpunit.de",
373
+ "role": "lead"
374
+ }
375
+ ],
376
+ "description": "The PHP Unit Testing framework.",
377
+ "homepage": "http://www.phpunit.de/",
378
+ "keywords": [
379
+ "phpunit",
380
+ "testing",
381
+ "xunit"
382
+ ],
383
+ "time": "2014-11-11 10:11:09"
384
+ },
385
+ {
386
+ "name": "phpunit/phpunit-mock-objects",
387
+ "version": "2.3.0",
388
+ "source": {
389
+ "type": "git",
390
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
391
+ "reference": "c63d2367247365f688544f0d500af90a11a44c65"
392
+ },
393
+ "dist": {
394
+ "type": "zip",
395
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/c63d2367247365f688544f0d500af90a11a44c65",
396
+ "reference": "c63d2367247365f688544f0d500af90a11a44c65",
397
+ "shasum": ""
398
+ },
399
+ "require": {
400
+ "doctrine/instantiator": "~1.0,>=1.0.1",
401
+ "php": ">=5.3.3",
402
+ "phpunit/php-text-template": "~1.2"
403
+ },
404
+ "require-dev": {
405
+ "phpunit/phpunit": "~4.3"
406
+ },
407
+ "suggest": {
408
+ "ext-soap": "*"
409
+ },
410
+ "type": "library",
411
+ "extra": {
412
+ "branch-alias": {
413
+ "dev-master": "2.3.x-dev"
414
+ }
415
+ },
416
+ "autoload": {
417
+ "classmap": [
418
+ "src/"
419
+ ]
420
+ },
421
+ "notification-url": "https://packagist.org/downloads/",
422
+ "license": [
423
+ "BSD-3-Clause"
424
+ ],
425
+ "authors": [
426
+ {
427
+ "name": "Sebastian Bergmann",
428
+ "email": "sb@sebastian-bergmann.de",
429
+ "role": "lead"
430
+ }
431
+ ],
432
+ "description": "Mock Object library for PHPUnit",
433
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
434
+ "keywords": [
435
+ "mock",
436
+ "xunit"
437
+ ],
438
+ "time": "2014-10-03 05:12:11"
439
+ },
440
+ {
441
+ "name": "sebastian/comparator",
442
+ "version": "1.0.1",
443
+ "source": {
444
+ "type": "git",
445
+ "url": "https://github.com/sebastianbergmann/comparator.git",
446
+ "reference": "e54a01c0da1b87db3c5a3c4c5277ddf331da4aef"
447
+ },
448
+ "dist": {
449
+ "type": "zip",
450
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e54a01c0da1b87db3c5a3c4c5277ddf331da4aef",
451
+ "reference": "e54a01c0da1b87db3c5a3c4c5277ddf331da4aef",
452
+ "shasum": ""
453
+ },
454
+ "require": {
455
+ "php": ">=5.3.3",
456
+ "sebastian/diff": "~1.1",
457
+ "sebastian/exporter": "~1.0"
458
+ },
459
+ "require-dev": {
460
+ "phpunit/phpunit": "~4.1"
461
+ },
462
+ "type": "library",
463
+ "extra": {
464
+ "branch-alias": {
465
+ "dev-master": "1.0.x-dev"
466
+ }
467
+ },
468
+ "autoload": {
469
+ "classmap": [
470
+ "src/"
471
+ ]
472
+ },
473
+ "notification-url": "https://packagist.org/downloads/",
474
+ "license": [
475
+ "BSD-3-Clause"
476
+ ],
477
+ "authors": [
478
+ {
479
+ "name": "Jeff Welch",
480
+ "email": "whatthejeff@gmail.com"
481
+ },
482
+ {
483
+ "name": "Volker Dusch",
484
+ "email": "github@wallbash.com"
485
+ },
486
+ {
487
+ "name": "Bernhard Schussek",
488
+ "email": "bschussek@2bepublished.at"
489
+ },
490
+ {
491
+ "name": "Sebastian Bergmann",
492
+ "email": "sebastian@phpunit.de"
493
+ }
494
+ ],
495
+ "description": "Provides the functionality to compare PHP values for equality",
496
+ "homepage": "http://www.github.com/sebastianbergmann/comparator",
497
+ "keywords": [
498
+ "comparator",
499
+ "compare",
500
+ "equality"
501
+ ],
502
+ "time": "2014-05-11 23:00:21"
503
+ },
504
+ {
505
+ "name": "sebastian/diff",
506
+ "version": "1.2.0",
507
+ "source": {
508
+ "type": "git",
509
+ "url": "https://github.com/sebastianbergmann/diff.git",
510
+ "reference": "5843509fed39dee4b356a306401e9dd1a931fec7"
511
+ },
512
+ "dist": {
513
+ "type": "zip",
514
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7",
515
+ "reference": "5843509fed39dee4b356a306401e9dd1a931fec7",
516
+ "shasum": ""
517
+ },
518
+ "require": {
519
+ "php": ">=5.3.3"
520
+ },
521
+ "require-dev": {
522
+ "phpunit/phpunit": "~4.2"
523
+ },
524
+ "type": "library",
525
+ "extra": {
526
+ "branch-alias": {
527
+ "dev-master": "1.2-dev"
528
+ }
529
+ },
530
+ "autoload": {
531
+ "classmap": [
532
+ "src/"
533
+ ]
534
+ },
535
+ "notification-url": "https://packagist.org/downloads/",
536
+ "license": [
537
+ "BSD-3-Clause"
538
+ ],
539
+ "authors": [
540
+ {
541
+ "name": "Kore Nordmann",
542
+ "email": "mail@kore-nordmann.de"
543
+ },
544
+ {
545
+ "name": "Sebastian Bergmann",
546
+ "email": "sebastian@phpunit.de"
547
+ }
548
+ ],
549
+ "description": "Diff implementation",
550
+ "homepage": "http://www.github.com/sebastianbergmann/diff",
551
+ "keywords": [
552
+ "diff"
553
+ ],
554
+ "time": "2014-08-15 10:29:00"
555
+ },
556
+ {
557
+ "name": "sebastian/environment",
558
+ "version": "1.2.0",
559
+ "source": {
560
+ "type": "git",
561
+ "url": "https://github.com/sebastianbergmann/environment.git",
562
+ "reference": "0d9bf79554d2a999da194a60416c15cf461eb67d"
563
+ },
564
+ "dist": {
565
+ "type": "zip",
566
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/0d9bf79554d2a999da194a60416c15cf461eb67d",
567
+ "reference": "0d9bf79554d2a999da194a60416c15cf461eb67d",
568
+ "shasum": ""
569
+ },
570
+ "require": {
571
+ "php": ">=5.3.3"
572
+ },
573
+ "require-dev": {
574
+ "phpunit/phpunit": "~4.3"
575
+ },
576
+ "type": "library",
577
+ "extra": {
578
+ "branch-alias": {
579
+ "dev-master": "1.2.x-dev"
580
+ }
581
+ },
582
+ "autoload": {
583
+ "classmap": [
584
+ "src/"
585
+ ]
586
+ },
587
+ "notification-url": "https://packagist.org/downloads/",
588
+ "license": [
589
+ "BSD-3-Clause"
590
+ ],
591
+ "authors": [
592
+ {
593
+ "name": "Sebastian Bergmann",
594
+ "email": "sebastian@phpunit.de"
595
+ }
596
+ ],
597
+ "description": "Provides functionality to handle HHVM/PHP environments",
598
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
599
+ "keywords": [
600
+ "Xdebug",
601
+ "environment",
602
+ "hhvm"
603
+ ],
604
+ "time": "2014-10-22 06:38:05"
605
+ },
606
+ {
607
+ "name": "sebastian/exporter",
608
+ "version": "1.0.2",
609
+ "source": {
610
+ "type": "git",
611
+ "url": "https://github.com/sebastianbergmann/exporter.git",
612
+ "reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0"
613
+ },
614
+ "dist": {
615
+ "type": "zip",
616
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c7d59948d6e82818e1bdff7cadb6c34710eb7dc0",
617
+ "reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0",
618
+ "shasum": ""
619
+ },
620
+ "require": {
621
+ "php": ">=5.3.3"
622
+ },
623
+ "require-dev": {
624
+ "phpunit/phpunit": "~4.0"
625
+ },
626
+ "type": "library",
627
+ "extra": {
628
+ "branch-alias": {
629
+ "dev-master": "1.0.x-dev"
630
+ }
631
+ },
632
+ "autoload": {
633
+ "classmap": [
634
+ "src/"
635
+ ]
636
+ },
637
+ "notification-url": "https://packagist.org/downloads/",
638
+ "license": [
639
+ "BSD-3-Clause"
640
+ ],
641
+ "authors": [
642
+ {
643
+ "name": "Jeff Welch",
644
+ "email": "whatthejeff@gmail.com"
645
+ },
646
+ {
647
+ "name": "Volker Dusch",
648
+ "email": "github@wallbash.com"
649
+ },
650
+ {
651
+ "name": "Bernhard Schussek",
652
+ "email": "bschussek@2bepublished.at"
653
+ },
654
+ {
655
+ "name": "Sebastian Bergmann",
656
+ "email": "sebastian@phpunit.de"
657
+ },
658
+ {
659
+ "name": "Adam Harvey",
660
+ "email": "aharvey@php.net"
661
+ }
662
+ ],
663
+ "description": "Provides the functionality to export PHP variables for visualization",
664
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
665
+ "keywords": [
666
+ "export",
667
+ "exporter"
668
+ ],
669
+ "time": "2014-09-10 00:51:36"
670
+ },
671
+ {
672
+ "name": "sebastian/version",
673
+ "version": "1.0.3",
674
+ "source": {
675
+ "type": "git",
676
+ "url": "https://github.com/sebastianbergmann/version.git",
677
+ "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43"
678
+ },
679
+ "dist": {
680
+ "type": "zip",
681
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43",
682
+ "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43",
683
+ "shasum": ""
684
+ },
685
+ "type": "library",
686
+ "autoload": {
687
+ "classmap": [
688
+ "src/"
689
+ ]
690
+ },
691
+ "notification-url": "https://packagist.org/downloads/",
692
+ "license": [
693
+ "BSD-3-Clause"
694
+ ],
695
+ "authors": [
696
+ {
697
+ "name": "Sebastian Bergmann",
698
+ "email": "sebastian@phpunit.de",
699
+ "role": "lead"
700
+ }
701
+ ],
702
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
703
+ "homepage": "https://github.com/sebastianbergmann/version",
704
+ "time": "2014-03-07 15:35:33"
705
+ },
706
+ {
707
+ "name": "symfony/yaml",
708
+ "version": "v2.5.6",
709
+ "target-dir": "Symfony/Component/Yaml",
710
+ "source": {
711
+ "type": "git",
712
+ "url": "https://github.com/symfony/Yaml.git",
713
+ "reference": "2d9f527449cabfa8543dd7fa3a466d6ae83d6726"
714
+ },
715
+ "dist": {
716
+ "type": "zip",
717
+ "url": "https://api.github.com/repos/symfony/Yaml/zipball/2d9f527449cabfa8543dd7fa3a466d6ae83d6726",
718
+ "reference": "2d9f527449cabfa8543dd7fa3a466d6ae83d6726",
719
+ "shasum": ""
720
+ },
721
+ "require": {
722
+ "php": ">=5.3.3"
723
+ },
724
+ "type": "library",
725
+ "extra": {
726
+ "branch-alias": {
727
+ "dev-master": "2.5-dev"
728
+ }
729
+ },
730
+ "autoload": {
731
+ "psr-0": {
732
+ "Symfony\\Component\\Yaml\\": ""
733
+ }
734
+ },
735
+ "notification-url": "https://packagist.org/downloads/",
736
+ "license": [
737
+ "MIT"
738
+ ],
739
+ "authors": [
740
+ {
741
+ "name": "Symfony Community",
742
+ "homepage": "http://symfony.com/contributors"
743
+ },
744
+ {
745
+ "name": "Fabien Potencier",
746
+ "email": "fabien@symfony.com"
747
+ }
748
+ ],
749
+ "description": "Symfony Yaml Component",
750
+ "homepage": "http://symfony.com",
751
+ "time": "2014-10-01 05:50:18"
752
+ }
753
+ ],
754
+ "aliases": [],
755
+ "minimum-stability": "stable",
756
+ "stability-flags": [],
757
+ "prefer-stable": false,
758
+ "platform": [],
759
+ "platform-dev": []
760
+ }
vendor/PHP_XLSXWriter/example-cli.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ include_once("xlsxwriter.class.php");
3
+ ini_set('display_errors', 0);
4
+ ini_set('log_errors', 1);
5
+ error_reporting(E_ALL & ~E_NOTICE);
6
+
7
+ $filename = "example.xlsx";
8
+
9
+ $rows = array(
10
+ array('2003','1','-50.5','2010-01-01 23:00:00','2012-12-31 23:00:00'),
11
+ array('2003','=B1', '23.5','2010-01-01 00:00:00','2012-12-31 00:00:00'),
12
+ );
13
+
14
+ $writer = new XLSXWriter();
15
+ $writer->setAuthor('Some Author');
16
+ foreach($rows as $row)
17
+ $writer->writeSheetRow('Sheet1', $row);
18
+
19
+ $writer->writeToFile('example.xlsx');
vendor/PHP_XLSXWriter/example.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ include_once("xlsxwriter.class.php");
3
+ ini_set('display_errors', 0);
4
+ ini_set('log_errors', 1);
5
+ error_reporting(E_ALL & ~E_NOTICE);
6
+
7
+ $filename = "example.xlsx";
8
+ header('Content-disposition: attachment; filename="'.XLSXWriter::sanitize_filename($filename).'"');
9
+ header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
10
+ header('Content-Transfer-Encoding: binary');
11
+ header('Cache-Control: must-revalidate');
12
+ header('Pragma: public');
13
+
14
+ $rows = array(
15
+ array('2003','1','-50.5','2010-01-01 23:00:00','2012-12-31 23:00:00'),
16
+ array('2003','=B1', '23.5','2010-01-01 00:00:00','2012-12-31 00:00:00'),
17
+ );
18
+
19
+ $writer = new XLSXWriter();
20
+ $writer->setAuthor('Some Author');
21
+ foreach($rows as $row)
22
+ $writer->writeSheetRow('Sheet1', $row);
23
+ $writer->writeToStdOut();
24
+ //$writer->writeToFile('example.xlsx');
25
+ //echo $writer->writeToString();
26
+ exit(0);
27
+
28
+
vendor/PHP_XLSXWriter/examples/ex00-simple.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $header = array(
6
+ 'c1-text'=>'string',//text
7
+ 'c2-text'=>'@',//text
8
+ 'c3-integer'=>'integer',
9
+ 'c4-integer'=>'0',
10
+ 'c5-price'=>'price',
11
+ 'c6-price'=>'#,##0.00',//custom
12
+ 'c7-date'=>'date',
13
+ 'c8-date'=>'YYYY-MM-DD',
14
+ );
15
+ $rows = array(
16
+ array('x101',102,103,104,105,106,'2018-01-07','2018-01-08'),
17
+ array('x201',202,203,204,205,206,'2018-02-07','2018-02-08'),
18
+ array('x301',302,303,304,305,306,'2018-03-07','2018-03-08'),
19
+ array('x401',402,403,404,405,406,'2018-04-07','2018-04-08'),
20
+ array('x501',502,503,504,505,506,'2018-05-07','2018-05-08'),
21
+ array('x601',602,603,604,605,606,'2018-06-07','2018-06-08'),
22
+ array('x701',702,703,704,705,706,'2018-07-07','2018-07-08'),
23
+ );
24
+ $writer = new XLSXWriter();
25
+
26
+ $writer->writeSheetHeader('Sheet1', $header);
27
+ foreach($rows as $row)
28
+ $writer->writeSheetRow('Sheet1', $row);
29
+
30
+ //$writer->writeSheet($rows,'Sheet1', $header);//or write the whole sheet in 1 call
31
+
32
+ $writer->writeToFile('xlsx-simple.xlsx');
33
+ //$writer->writeToStdOut();
34
+ //echo $writer->writeToString();
35
+
vendor/PHP_XLSXWriter/examples/ex01-multiple-sheets.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $header = array(
6
+ 'year'=>'string',
7
+ 'month'=>'string',
8
+ 'amount'=>'price',
9
+ 'first_event'=>'datetime',
10
+ 'second_event'=>'date',
11
+ );
12
+ $data1 = array(
13
+ array('2003','1','-50.5','2010-01-01 23:00:00','2012-12-31 23:00:00'),
14
+ array('2003','=B2', '23.5','2010-01-01 00:00:00','2012-12-31 00:00:00'),
15
+ array('2003',"'=B2", '23.5','2010-01-01 00:00:00','2012-12-31 00:00:00'),
16
+ );
17
+ $data2 = array(
18
+ array('2003','01','343.12','4000000000'),
19
+ array('2003','02','345.12','2000000000'),
20
+ );
21
+ $writer = new XLSXWriter();
22
+ $writer->writeSheetHeader('Sheet1', $header);
23
+ foreach($data1 as $row)
24
+ $writer->writeSheetRow('Sheet1', $row);
25
+ foreach($data2 as $row)
26
+ $writer->writeSheetRow('Sheet2', $row);
27
+
28
+ $writer->writeToFile('xlsx-sheets.xlsx');
29
+ //$writer->writeToStdOut();
30
+ //echo $writer->writeToString();
31
+
32
+ exit(0);
33
+
34
+
vendor/PHP_XLSXWriter/examples/ex02-formats.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $sheet1header = array(
6
+ 'c1-string'=>'string',
7
+ 'c2-integer'=>'integer',
8
+ 'c3-custom-integer'=>'0',
9
+ 'c4-custom-1decimal'=>'0.0',
10
+ 'c5-custom-2decimal'=>'0.00',
11
+ 'c6-custom-percent'=>'0%',
12
+ 'c7-custom-percent1'=>'0.0%',
13
+ 'c8-custom-percent2'=>'0.00%',
14
+ 'c9-custom-text'=>'@',//text
15
+ );
16
+ $sheet2header = array(
17
+ 'col1-date'=>'date',
18
+ 'col2-datetime'=>'datetime',
19
+ 'col3-time'=>'time',
20
+ 'custom-date1'=>'YYYY-MM-DD',
21
+ 'custom-date2'=>'MM/DD/YYYY',
22
+ 'custom-date3'=>'DD-MMM-YYYY HH:MM AM/PM',
23
+ 'custom-date4'=>'MM/DD/YYYY HH:MM:SS',
24
+ 'custom-date5'=>'YYYY-MM-DD HH:MM:SS',
25
+ 'custom-date6'=>'YY MMMM',
26
+ 'custom-date7'=>'QQ YYYY',
27
+ 'custom-time1'=>'HH:MM',
28
+ 'custom-time2'=>'HH:MM:SS',
29
+ );
30
+ $sheet3header = array(
31
+ 'col1-dollar'=>'dollar',
32
+ 'col2-euro'=>'euro',
33
+ 'custom-amount1'=>'0',
34
+ 'custom-amount2'=>'0.0',//1 decimal place
35
+ 'custom-amount3'=>'0.00',//2 decimal places
36
+ 'custom-currency1'=>'#,##0.00',//currency 2 decimal places, no currency/dollar sign
37
+ 'custom-currency2'=>'[$$-1009]#,##0.00;[RED]-[$$-1009]#,##0.00',//w/dollar sign
38
+ 'custom-currency3'=>'#,##0.00 [$€-407];[RED]-#,##0.00 [$€-407]',//w/euro sign
39
+ 'custom-currency4'=>'[$¥-411]#,##0;[RED]-[$¥-411]#,##0', //japanese yen
40
+ 'custom-scientific'=>'0.00E+000',//-1.23E+003 scientific notation
41
+ );
42
+ $pi = 3.14159;
43
+ $date = '2018-12-31 23:59:59';
44
+ $time = '23:59:59';
45
+ $amount = '5120.5';
46
+
47
+ $writer = new XLSXWriter();
48
+ $writer->setAuthor('Some Author');
49
+ $writer->writeSheetHeader('BasicFormats',$sheet1header);
50
+ $writer->writeSheetRow('BasicFormats',array($pi,$pi,$pi,$pi,$pi,$pi,$pi,$pi,$pi) );
51
+ $writer->writeSheetHeader('Dates',$sheet2header);
52
+ $writer->writeSheetRow('Dates',array($date,$date,$date,$date,$date,$date,$date,$date,$date,$date,$time,$time) );
53
+ $writer->writeSheetHeader('Currencies',$sheet3header);
54
+ $writer->writeSheetRow('Currencies',array($amount,$amount,$amount,$amount,$amount,$amount,$amount,$amount,$amount) );
55
+ $writer->writeToFile('xlsx-formats.xlsx');
56
+ //$writer->writeToStdOut();
57
+ //echo $writer->writeToString();
58
+
59
+ echo '#'.floor((memory_get_peak_usage())/1024/1024)."MB"."\n";
60
+ exit(0);
61
+
62
+
63
+
64
+
65
+
vendor/PHP_XLSXWriter/examples/ex03-styles.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+
6
+ $writer = new XLSXWriter();
7
+ $styles1 = array( 'font'=>'Arial','font-size'=>10,'font-style'=>'bold', 'fill'=>'#eee', 'halign'=>'center', 'border'=>'left,right,top,bottom');
8
+ $styles2 = array( ['font-size'=>6],['font-size'=>8],['font-size'=>10],['font-size'=>16] );
9
+ $styles3 = array( ['font'=>'Arial'],['font'=>'Courier New'],['font'=>'Times New Roman'],['font'=>'Comic Sans MS']);
10
+ $styles4 = array( ['font-style'=>'bold'],['font-style'=>'italic'],['font-style'=>'underline'],['font-style'=>'strikethrough']);
11
+ $styles5 = array( ['color'=>'#f00'],['color'=>'#0f0'],['color'=>'#00f'],['color'=>'#666']);
12
+ $styles6 = array( ['fill'=>'#ffc'],['fill'=>'#fcf'],['fill'=>'#ccf'],['fill'=>'#cff']);
13
+ $styles7 = array( 'border'=>'left,right,top,bottom');
14
+ $styles8 = array( ['halign'=>'left'],['halign'=>'right'],['halign'=>'center'],['halign'=>'none']);
15
+ $styles9 = array( array(),['border'=>'left,top,bottom'],['border'=>'top,bottom'],['border'=>'top,bottom,right']);
16
+
17
+
18
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $styles1 );
19
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $styles2 );
20
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $styles3 );
21
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $styles4 );
22
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $styles5 );
23
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $styles6 );
24
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $styles7 );
25
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $styles8 );
26
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $styles9 );
27
+ $writer->writeToFile('xlsx-styles.xlsx');
28
+
29
+
vendor/PHP_XLSXWriter/examples/ex04-colors.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $writer = new XLSXWriter();
6
+ $colors = array('ff','cc','99','66','33','00');
7
+ foreach($colors as $b) {
8
+ foreach($colors as $g) {
9
+ $rowdata = array();
10
+ $rowstyle = array();
11
+ foreach($colors as $r) {
12
+ $rowdata[] = "#$r$g$b";
13
+ $rowstyle[] = array('fill'=>"#$r$g$b");
14
+ }
15
+ $writer->writeSheetRow('Sheet1', $rowdata, $rowstyle );
16
+ }
17
+ }
18
+ $writer->writeToFile('xlsx-colors.xlsx');
vendor/PHP_XLSXWriter/examples/ex05-numbers-250k-rows.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $writer = new XLSXWriter();
6
+ $writer->writeSheetHeader('Sheet1', array('c1'=>'integer','c2'=>'integer','c3'=>'integer','c4'=>'integer') );//optional
7
+ for($i=0; $i<250000; $i++)
8
+ {
9
+ $writer->writeSheetRow('Sheet1', array(rand()%10000,rand()%10000,rand()%10000,rand()%10000) );
10
+ }
11
+ $writer->writeToFile('xlsx-numbers-250k.xlsx');
12
+ echo '#'.floor((memory_get_peak_usage())/1024/1024)."MB"."\n";
vendor/PHP_XLSXWriter/examples/ex06-strings-250k-rows.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $chars = "abcdefghijklmnopqrstuvwxyz0123456789 ";
6
+ $s = '';
7
+ for($j=0; $j<16192;$j++)
8
+ $s.= $chars[rand()%36];
9
+
10
+
11
+ $writer = new XLSXWriter();
12
+ $writer->writeSheetHeader('Sheet1', array('c1'=>'string','c2'=>'string','c3'=>'string','c4'=>'string') );//optional
13
+ for($i=0; $i<250000; $i++)
14
+ {
15
+ $s1 = substr($s, rand()%4000, rand()%5+5);
16
+ $s2 = substr($s, rand()%8000, rand()%5+5);
17
+ $s3 = substr($s, rand()%12000, rand()%5+5);
18
+ $s4 = substr($s, rand()%16000, rand()%5+5);
19
+ $writer->writeSheetRow('Sheet1', array($s1, $s2, $s3, $s4) );
20
+ }
21
+ $writer->writeToFile('xlsx-strings-250k.xlsx');
22
+ echo '#'.floor((memory_get_peak_usage())/1024/1024)."MB"."\n";
23
+
vendor/PHP_XLSXWriter/examples/ex07-widths.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+
6
+ $writer = new XLSXWriter();
7
+ $writer->writeSheetHeader('Sheet1', $rowdata = array(300,234,456,789), $col_options = ['widths'=>[10,20,30,40]] );
8
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $row_options = ['height'=>20] );
9
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $row_options = ['height'=>30] );
10
+ $writer->writeSheetRow('Sheet1', $rowdata = array(300,234,456,789), $row_options = ['height'=>40] );
11
+ $writer->writeToFile('xlsx-widths.xlsx');
12
+
13
+
vendor/PHP_XLSXWriter/examples/ex08-advanced.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $writer = new XLSXWriter();
6
+ $keywords = array('some','interesting','keywords');
7
+
8
+ $writer->setTitle('Some Title');
9
+ $writer->setSubject('Some Subject');
10
+ $writer->setAuthor('Some Author');
11
+ $writer->setCompany('Some Company');
12
+ $writer->setKeywords($keywords);
13
+ $writer->setDescription('Some interesting description');
14
+ $writer->setTempDir(sys_get_temp_dir());//set custom tempdir
15
+
16
+ //----
17
+ $sheet1 = 'merged_cells';
18
+ $header = array("string","string","string","string","string");
19
+ $rows = array(
20
+ array("Merge Cells Example"),
21
+ array(100, 200, 300, 400, 500),
22
+ array(110, 210, 310, 410, 510),
23
+ );
24
+ $writer->writeSheetHeader($sheet1, $header, $col_options = ['suppress_row'=>true] );
25
+ foreach($rows as $row)
26
+ $writer->writeSheetRow($sheet1, $row);
27
+ $writer->markMergedCell($sheet1, $start_row=0, $start_col=0, $end_row=0, $end_col=4);
28
+
29
+ //----
30
+ $sheet2 = 'utf8';
31
+ $rows = array(
32
+ array('Spreadsheet','_'),
33
+ array("Hoja de cálculo", "Hoja de c\xc3\xa1lculo"),
34
+ array("Електронна таблица", "\xd0\x95\xd0\xbb\xd0\xb5\xd0\xba\xd1\x82\xd1\x80\xd0\xbe\xd0\xbd\xd0\xbd\xd0\xb0 \xd1\x82\xd0\xb0\xd0\xb1\xd0\xbb\xd0\xb8\xd1\x86\xd0\xb0"),//utf8 encoded
35
+ array("電子試算表", "\xe9\x9b\xbb\xe5\xad\x90\xe8\xa9\xa6\xe7\xae\x97\xe8\xa1\xa8"),//utf8 encoded
36
+ );
37
+ $writer->writeSheet($rows, $sheet2);
38
+
39
+ //----
40
+ $sheet3 = 'fonts';
41
+ $format = array('font'=>'Arial','font-size'=>10,'font-style'=>'bold,italic', 'fill'=>'#eee','color'=>'#f00','fill'=>'#ffc', 'border'=>'top,bottom', 'halign'=>'center');
42
+ $writer->writeSheetRow($sheet3, $row=array(101,102,103,104,105,106,107,108,109,110), $format);
43
+ $writer->writeSheetRow($sheet3, $row=array(201,202,203,204,205,206,207,208,209,210), $format);
44
+
45
+
46
+ //----
47
+ $sheet4 = 'row_options';
48
+ $writer->writeSheetHeader($sheet4, ["col1"=>"string", "col2"=>"string"], $col_options = array('widths'=>[10,10]) );
49
+ $writer->writeSheetRow($sheet4, array(101,'this text will wrap' ), $row_options = array('height'=>30,'wrap_text'=>true));
50
+ $writer->writeSheetRow($sheet4, array(201,'this text is hidden' ), $row_options = array('height'=>30,'hidden'=>true));
51
+ $writer->writeSheetRow($sheet4, array(301,'this text will not wrap'), $row_options = array('height'=>30,'collapsed'=>true));
52
+ $writer->writeToFile('xlsx-advanced.xlsx');
53
+
54
+
vendor/PHP_XLSXWriter/examples/ex09-autofilter.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $chars = 'abcdefgh';
6
+
7
+ $writer = new XLSXWriter();
8
+ $writer->writeSheetHeader('Sheet1', array('col-string'=>'string','col-numbers'=>'integer','col-timestamps'=>'datetime'), ['auto_filter'=>true, 'widths'=>[15,15,30]] );
9
+ for($i=0; $i<1000; $i++)
10
+ {
11
+ $writer->writeSheetRow('Sheet1', array(
12
+ str_shuffle($chars),
13
+ rand()%10000,
14
+ date('Y-m-d H:i:s',time()-(rand()%31536000))
15
+ ));
16
+ }
17
+ $writer->writeToFile('xlsx-autofilter.xlsx');
18
+ echo '#'.floor((memory_get_peak_usage())/1024/1024)."MB"."\n";
vendor/PHP_XLSXWriter/examples/ex10-freeze-rows-columns.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $chars = 'abcdefgh';
6
+
7
+ $writer = new XLSXWriter();
8
+ $writer->writeSheetHeader('Sheet1', array('c1'=>'string','c2'=>'integer','c3'=>'integer','c4'=>'integer','c5'=>'integer'), ['freeze_rows'=>1, 'freeze_columns'=>1] );
9
+ for($i=0; $i<250; $i++)
10
+ {
11
+ $writer->writeSheetRow('Sheet1', array(
12
+ str_shuffle($chars),
13
+ rand()%10000,
14
+ rand()%10000,
15
+ rand()%10000,
16
+ rand()%10000
17
+ ));
18
+ }
19
+ $writer->writeToFile('xlsx-freeze-rows-columns.xlsx');
20
+ echo '#'.floor((memory_get_peak_usage())/1024/1024)."MB"."\n";
vendor/PHP_XLSXWriter/examples/ex11-right-to-left.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ set_include_path( get_include_path().PATH_SEPARATOR."..");
3
+ include_once("xlsxwriter.class.php");
4
+
5
+ $header = array(
6
+ 'c1-text'=>'string',//text
7
+ 'c2-text'=>'@',//text
8
+ );
9
+ $rows = array(
10
+ array('abcdefg','hijklmnop'),
11
+ );
12
+ $writer = new XLSXWriter();
13
+ $writer->setRightToLeft(true);
14
+
15
+ $writer->writeSheetHeader('Sheet1', $header);
16
+ foreach($rows as $row)
17
+ $writer->writeSheetRow('Sheet1', $row);
18
+ $writer->writeToFile('xlsx-right-to-left.xlsx');
19
+
vendor/PHP_XLSXWriter/testbench/README.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ README
2
+ ------
3
+
4
+ run_test_and_diff.sh
5
+
6
+ Just a quick tool for diffing spreadsheets, from a baseline openoffice/libreoffice spreadsheet.
7
+ Requires xmllint and meld as command line tools in linux. The idea is you can manipulate the
8
+ xlsx spreadsheet and then see what the resulting xml is, and diff it with your test.xlsx
9
+
10
+ ```sudo apt-get install xmllint libxml2-utils```
11
+
12
+ xlsxwriter.class.Test.php
13
+
14
+ A simple PHPUnit test for a basic spreadsheet
vendor/PHP_XLSXWriter/testbench/diff-two.sh ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ if [ ! -f "$1" ] || [ ! -f "$2" ]; then
3
+ echo "Example Usage: $0 f1.xlsx f2.xlsx";
4
+ exit
5
+ fi
6
+ ./extract.sh $1
7
+ ./extract.sh $2
8
+ echo "Now, run this command:"
9
+ echo " meld openoffice/ test/";
10
+ #export DISPLAY=:0 && meld openoffice/ test/;
11
+
vendor/PHP_XLSXWriter/testbench/extract.sh ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ FILENAME=`basename --suffix=.xlsx $1`
3
+ DIRNAME=$FILENAME"_dir"
4
+ if [ "" == "$1" ]; then
5
+ echo "Example Usage: $0 spreadsheet.xlsx";
6
+ exit
7
+ fi
8
+ if [ ! -f "$1" ]; then
9
+ echo "Example Usage: $0 spreadsheet.xlsx";
10
+ exit
11
+ fi
12
+ mkdir -p $DIRNAME;
13
+ cp $1 $DIRNAME;
14
+ cd $DIRNAME;
15
+ unzip -o $1;
16
+
17
+ for FILE in *.xml;
18
+ do
19
+ xmllint --format "$FILE" > temp.xml;
20
+ mv temp.xml $FILE;
21
+ done;
22
+ for FILE in */*.xml
23
+ do
24
+ xmllint --format "$FILE" > temp.xml;
25
+ mv temp.xml $FILE;
26
+ done;
27
+ for FILE in */*/*.xml
28
+ do
29
+ xmllint --format "$FILE" > temp.xml;
30
+ mv temp.xml $FILE;
31
+ done;
32
+ xmllint --format "xl/_rels/workbook.xml.rels" > temp.xml;
33
+ mv temp.xml xl/_rels/workbook.xml.rels;
34
+ cd ..;
35
+ exit
36
+
vendor/PHP_XLSXWriter/testbench/openoffice.xlsx ADDED
Binary file
vendor/PHP_XLSXWriter/testbench/pairs/formats.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ include_once("../../xlsxwriter.class.php");
3
+
4
+ $writer = new XLSXWriter();
5
+ $keywords = array('some','interesting','keywords');
6
+
7
+ $writer->setTitle('Some Title');
8
+ $writer->setSubject('Some Subject');
9
+ $writer->setAuthor('Some Author');
10
+ $writer->setCompany('Some Company');
11
+ $writer->setKeywords($keywords);
12
+ $writer->setDescription('Some interesting description');
13
+
14
+ $header = array(
15
+ 'General'=>'string',
16
+ 'Simple Integer'=>'0',
17
+ '2 Decimal Places Integer'=>'0.00',
18
+ 'Integer 1000s Group'=>'#,##0',
19
+ '1000s,Decimal,Leading Zero'=>'#,##0.00',
20
+ '1000s,Decimal,No Leading Zero'=>'#,###.00',
21
+ 'Negative In Parentheses'=>'#,##0_);(#,##0)',
22
+ 'Negative In Parentheses With Decimal'=>'#,##0.00_);(#,##0.00)',
23
+ );
24
+ $row = array('1000','2000','3000','4000','0.50','0.50','-50','-50');
25
+ $writer->writeSheet(array( $row ),'Number',$header);
26
+
27
+ $header = array(
28
+ 'Whole Percent'=>'0%',
29
+ 'Decimal Percent'=>'0.00%',
30
+ );
31
+ $row = array('1','1');
32
+ $writer->writeSheet(array( $row ),'Percent',$header);
33
+
34
+ $header = array(
35
+ 'USD'=>'[$$-409]#,##0.00;[RED]-[$$-409]#,##0.00',
36
+ 'CAD'=>'[$$-1009]#,##0.00;[RED]-[$$-1009]#,##0.00',
37
+ 'Euro'=>'#,##0.00 [$€-407];[RED]-#,##0.00 [$€-407]',
38
+ 'JPY'=>'[$¥-411]#,##0;[RED]-[$¥-411]#,##0',
39
+ 'CNY'=>'[$¥-804]#,##0.00;[RED]-[$¥-804]#,##0.00',
40
+ );
41
+ $row = array('1000','2000','3000','4000','5000');
42
+ $writer->writeSheet(array( $row ) ,'Currency',$header);
43
+
44
+ $header = array(
45
+ 'M/D/YY'=>'M/D/YY',
46
+ 'MM/DD/YYYY'=>'MM/DD/YYYY',
47
+ 'YYYY-MM-DD'=>'YYYY-MM-DD',
48
+ 'YYYY-MM-DD HH:MM:SS'=>'YYYY-MM-DD HH:MM:SS',
49
+ 'NN'=>'NN',
50
+ 'NNN'=>'NNN',
51
+ 'NNNN'=>'NNNN',
52
+ 'D'=>'D',
53
+ 'DD'=>'DD',
54
+ 'M'=>'M',
55
+ 'MM'=>'MM',
56
+ 'MMM'=>'MMM',
57
+ 'MMMM'=>'MMMM',
58
+ 'YY'=>'YY',
59
+ 'YYYY'=>'YYYY',
60
+ 'Q YY'=>'Q YY',
61
+ 'Q YYYY'=>'Q YYYY',
62
+ );
63
+ $row = array('1999-01-01','1999-01-01','1999-12-31','1999-12-31 00:00:00',
64
+ '1999-12-31','1999-12-31','1999-12-31',
65
+ '1999-12-31','1999-12-31','1999-12-31',
66
+ '1999-12-31','1999-12-31','1999-12-31',
67
+ '1999-12-31','1999-12-31','1999-12-31',
68
+ '1999-12-31');
69
+ $writer->writeSheet(array( $row ) ,'Date',$header);
70
+
71
+ $header = array(
72
+ 'HH:MM'=>'HH:MM',
73
+ 'HH:MM:SS'=>'HH:MM:SS',
74
+ 'HH:MM AM/PM'=>'HH:MM AM/PM',
75
+ 'HH:MM:SS AM/PM'=>'HH:MM:SS AM/PM',
76
+ );
77
+ $row = array('12-31-1999 01:23:00','12-31-1999 01:23:00','12-31-1999 01:23:00','12-31-1999 01:23:00');
78
+ $writer->writeSheet(array( $row ) ,'Time',$header);
79
+
80
+ $writer->writeToFile('formats.xlsx');
81
+
82
+
83
+
84
+
vendor/PHP_XLSXWriter/testbench/pairs/formats_openoffice.xlsx ADDED
Binary file
vendor/PHP_XLSXWriter/testbench/pairs/test.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ include_once("../../xlsxwriter.class.php");
3
+
4
+ $writer = new XLSXWriter();
5
+ $keywords = array('some','interesting','keywords');
6
+
7
+ $writer->setTitle('Some Title');
8
+ $writer->setSubject('Some Subject');
9
+ $writer->setAuthor('Some Author');
10
+ $writer->setCompany('Some Company');
11
+ $writer->setKeywords($keywords);
12
+ $writer->setDescription('Some interesting description');
13
+
14
+ $header = array(
15
+ 'General'=>'string',
16
+ 'Simple Integer'=>'0',
17
+ '2 Decimal Places Integer'=>'0.00',
18
+ 'Integer 1000s Group'=>'#,##0',
19
+ '1000s,Decimal,Leading Zero'=>'#,##0.00',
20
+ '1000s,Decimal,No Leading Zero'=>'#,###.00',
21
+ 'Negative In Parentheses'=>'#,##0_);(#,##0)',
22
+ 'Negative In Parentheses With Decimal'=>'#,##0.00_);(#,##0.00)',
23
+ );
24
+ $row = array('1000','2000','3000','4000','0.50','0.50','-50','-50');
25
+ $writer->writeSheet(array( $row ),'Number',$header);
26
+
27
+ $header = array(
28
+ 'Whole Percent'=>'0%',
29
+ 'Decimal Percent'=>'0.00%',
30
+ );
31
+ $row = array('1','1');
32
+ $writer->writeSheet(array( $row ),'Percent',$header);
33
+
34
+ $header = array(
35
+ 'USD'=>'[$$-409]#,##0.00;[RED]-[$$-409]#,##0.00',
36
+ 'CAD'=>'[$$-1009]#,##0.00;[RED]-[$$-1009]#,##0.00',
37
+ 'Euro'=>'#,##0.00 [$€-407];[RED]-#,##0.00 [$€-407]',
38
+ 'JPY'=>'[$¥-411]#,##0;[RED]-[$¥-411]#,##0',
39
+ 'CNY'=>'[$¥-804]#,##0.00;[RED]-[$¥-804]#,##0.00',
40
+ );
41
+ $row = array('1000','2000','3000','4000','5000');
42
+ $writer->writeSheet(array( $row ) ,'Currency',$header);
43
+
44
+ $header = array(
45
+ 'M/D/YY'=>'M/D/YY',
46
+ 'MM/DD/YYYY'=>'MM/DD/YYYY',
47
+ 'YYYY-MM-DD'=>'YYYY-MM-DD',
48
+ 'YYYY-MM-DD HH:MM:SS'=>'YYYY-MM-DD HH:MM:SS',
49
+ 'NN'=>'NN',
50
+ 'NNN'=>'NNN',
51
+ 'NNNN'=>'NNNN',
52
+ 'D'=>'D',
53
+ 'DD'=>'DD',
54
+ 'M'=>'M',
55
+ 'MM'=>'MM',
56
+ 'MMM'=>'MMM',
57
+ 'MMMM'=>'MMMM',
58
+ 'YY'=>'YY',
59
+ 'YYYY'=>'YYYY',
60
+ 'Q YY'=>'Q YY',
61
+ 'Q YYYY'=>'Q YYYY',
62
+ );
63
+ $row = array('1999-01-01','1999-01-01','1999-12-31','1999-12-31 00:00:00',
64
+ '1999-12-31','1999-12-31','1999-12-31',
65
+ '1999-12-31','1999-12-31','1999-12-31',
66
+ '1999-12-31','1999-12-31','1999-12-31',
67
+ '1999-12-31','1999-12-31','1999-12-31',
68
+ '1999-12-31');
69
+ $writer->writeSheet(array( $row ) ,'Date',$header);
70
+
71
+ $header = array(
72
+ 'HH:MM'=>'HH:MM',
73
+ 'HH:MM:SS'=>'HH:MM:SS',
74
+ 'HH:MM AM/PM'=>'HH:MM AM/PM',
75
+ 'HH:MM:SS AM/PM'=>'HH:MM:SS AM/PM',
76
+ );
77
+ $row = array('12-31-1999 01:23:00','12-31-1999 01:23:00','12-31-1999 01:23:00','12-31-1999 01:23:00');
78
+ $writer->writeSheet(array( $row ) ,'Time',$header);
79
+
80
+ $writer->writeToFile('formats_.xlsx');
81
+
82
+
83
+
84
+
vendor/PHP_XLSXWriter/testbench/test.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ include_once("../xlsxwriter.class.php");
3
+
4
+ $header = array(
5
+ 'year'=>'string',
6
+ 'month'=>'string',
7
+ 'amount'=>'money',
8
+ 'first_event'=>'datetime',
9
+ 'second_event'=>'date',
10
+ );
11
+ $data1 = array(
12
+ array('2003','1','-50.5','2010-01-01 23:00:00','2012-12-31 23:00:00'),
13
+ array('2003','=B2', '23.5','2010-01-01 00:00:00','2012-12-31 00:00:00'),
14
+ );
15
+ $data2 = array(
16
+ array('2003','01','343.12'),
17
+ array('2003','02','345.12'),
18
+ );
19
+ $writer = new XLSXWriter();
20
+ $keywords = array('some','interesting','keywords');
21
+
22
+ $writer->setTitle('Some Title');
23
+ $writer->setSubject('Some Subject');
24
+ $writer->setAuthor('Some Author');
25
+ $writer->setCompany('Some Company');
26
+ $writer->setKeywords($keywords);
27
+ $writer->setDescription('Some interesting description');
28
+ $writer->writeSheet($data1,'Sheet1',$header);
29
+ $writer->writeSheet($data2,'Sheet2');
30
+ $writer->writeToFile('test.xlsx');
31
+
32
+
33
+
vendor/PHP_XLSXWriter/testbench/test.xlsx ADDED
Binary file
vendor/PHP_XLSXWriter/testbench/xlsxwriter.class.Test.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ include_once __DIR__.'/../vendor/autoload.php';
4
+
5
+ //TODO test double:writeSheetHeader
6
+ //TODO test invalid UTF8
7
+ //TODO test outoforder writeSheetRow('Sheet1',());
8
+
9
+ class _XLSXWriter_ extends XLSXWriter
10
+ {
11
+ public function writeCell(XLSXWriter_BuffererWriter &$file, $row_number, $column_number, $value, $cell_format) {
12
+ return call_user_func_array('parent::writeCell', func_get_args());
13
+ }
14
+ }
15
+ //Just a simple test, by no means comprehensive
16
+
17
+ class XLSXWriterTest extends PHPUnit_Framework_TestCase
18
+ {
19
+ /**
20
+ * @covers XLSXWriter::writeCell
21
+ */
22
+ public function testWriteCell()
23
+ {
24
+ $filename = tempnam("/tmp", "xlsx_writer");
25
+ $file_writer = new XLSXWriter_BuffererWriter($filename);
26
+
27
+ $xlsx_writer = new _XLSXWriter_();
28
+ $xlsx_writer->writeCell($file_writer, 0, 0, '0123', 'string');
29
+ $file_writer->close();
30
+ $cell_xml = file_get_contents($filename);
31
+ $this->assertNotEquals('<c r="A1" s="0" t="n"><v>123</v></c>', $cell_xml);
32
+ $this->assertEquals('<c r="A1" s="0" t="s"><v>0</v></c>', $cell_xml);//0123 should be the 0th index of the shared string array
33
+ @unlink($filename);
34
+ }
35
+
36
+ /**
37
+ * @covers XLSXWriter::writeToFile
38
+ */
39
+ public function testWriteToFile()
40
+ {
41
+ $filename = tempnam("/tmp", "xlsx_writer");
42
+
43
+ $header = array('0'=>'string','1'=>'string','2'=>'string','3'=>'string');
44
+ $sheet = array(
45
+ array('55','66','77','88'),
46
+ array('10','11','12','13'),
47
+ );
48
+
49
+ $xlsx_writer = new XLSXWriter();
50
+ $xlsx_writer->writeSheet($sheet,'mysheet',$header);
51
+ $xlsx_writer->writeToFile($filename);
52
+
53
+ $zip = new ZipArchive();
54
+ $r = $zip->open($filename);
55
+ $this->assertTrue($r);
56
+
57
+ $r = $zip->numFiles>0 ? true : false;
58
+ $this->assertTrue($r);
59
+
60
+ $out_sheet = array();
61
+ for($z=0; $z<$zip->numFiles; $z++)
62
+ {
63
+ $inside_zip_filename = $zip->getNameIndex($z);
64
+ if (preg_match("/sheet(\d+).xml/", basename($inside_zip_filename)))
65
+ {
66
+ $out_sheet = $this->stripCellsFromSheetXML($zip->getFromName($inside_zip_filename));
67
+ array_shift($out_sheet);
68
+ $out_sheet = array_values($out_sheet);
69
+ }
70
+ }
71
+ $zip->close();
72
+ @unlink($filename);
73
+
74
+ $r1 = self::array_diff_assoc_recursive($out_sheet, $sheet);
75
+ $r2 = self::array_diff_assoc_recursive($sheet, $out_sheet);
76
+ $this->assertEmpty($r1);
77
+ $this->assertEmpty($r2);
78
+ }
79
+
80
+ private function stripCellsFromSheetXML($sheet_xml)
81
+ {
82
+ $output=array();
83
+ $xml = new SimpleXMLElement($sheet_xml);
84
+ $i=0;
85
+ foreach($xml->sheetData->row as $row)
86
+ {
87
+ $j=0;
88
+ foreach($row->c as $c)
89
+ {
90
+ $output[$i][$j] = (string)$c->v;
91
+ $j++;
92
+ }
93
+ $i++;
94
+ }
95
+ return $output;
96
+ }
97
+
98
+ public static function array_diff_assoc_recursive($array1, $array2)
99
+ {
100
+ foreach($array1 as $key => $value)
101
+ {
102
+ if(is_array($value))
103
+ {
104
+ if(!isset($array2[$key]) || !is_array($array2[$key]))
105
+ {
106
+ $difference[$key] = $value;
107
+ }
108
+ else
109
+ {
110
+ $new_diff = self::array_diff_assoc_recursive($value, $array2[$key]);
111
+ if(!empty($new_diff))
112
+ {
113
+ $difference[$key] = $new_diff;
114
+ }
115
+ }
116
+ }
117
+ else if(!isset($array2[$key]) || $array2[$key] != $value)
118
+ {
119
+ $difference[$key] = $value;
120
+ }
121
+ }
122
+ return !isset($difference) ? array() : $difference;
123
+ }
124
+ }
vendor/PHP_XLSXWriter/xlsxwriter.class.php ADDED
@@ -0,0 +1,972 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * @license MIT License
4
+ * */
5
+
6
+ class XLSXWriter
7
+ {
8
+ //http://www.ecma-international.org/publications/standards/Ecma-376.htm
9
+ //http://officeopenxml.com/SSstyles.php
10
+ //------------------------------------------------------------------
11
+ //http://office.microsoft.com/en-us/excel-help/excel-specifications-and-limits-HP010073849.aspx
12
+ const EXCEL_2007_MAX_ROW=1048576;
13
+ const EXCEL_2007_MAX_COL=16384;
14
+ //------------------------------------------------------------------
15
+ protected $title;
16
+ protected $subject;
17
+ protected $author;
18
+ protected $isRightToLeft;
19
+ protected $company;
20
+ protected $description;
21
+ protected $keywords = array();
22
+
23
+ protected $current_sheet;
24
+ protected $sheets = array();
25
+ protected $temp_files = array();
26
+ protected $cell_styles = array();
27
+ protected $number_formats = array();
28
+
29
+ public function __construct()
30
+ {
31
+ defined('ENT_XML1') or define('ENT_XML1',16);//for php 5.3, avoid fatal error
32
+ date_default_timezone_get() or date_default_timezone_set('UTC');//php.ini missing tz, avoid warning
33
+ is_writeable($this->tempFilename()) or self::log("Warning: tempdir ".sys_get_temp_dir()." not writeable, use ->setTempDir()");
34
+ class_exists('ZipArchive') or self::log("Error: ZipArchive class does not exist");
35
+ $this->addCellStyle($number_format='GENERAL', $style_string=null);
36
+ }
37
+
38
+ public function setTitle($title='') { $this->title=$title; }
39
+ public function setSubject($subject='') { $this->subject=$subject; }
40
+ public function setAuthor($author='') { $this->author=$author; }
41
+ public function setCompany($company='') { $this->company=$company; }
42
+ public function setKeywords($keywords='') { $this->keywords=$keywords; }
43
+ public function setDescription($description='') { $this->description=$description; }
44
+ public function setTempDir($tempdir='') { $this->tempdir=$tempdir; }
45
+ public function setRightToLeft($isRightToLeft=false){ $this->isRightToLeft=$isRightToLeft; }
46
+
47
+ public function __destruct()
48
+ {
49
+ if (!empty($this->temp_files)) {
50
+ foreach($this->temp_files as $temp_file) {
51
+ @unlink($temp_file);
52
+ }
53
+ }
54
+ }
55
+
56
+ protected function tempFilename()
57
+ {
58
+ $tempdir = !empty($this->tempdir) ? $this->tempdir : sys_get_temp_dir();
59
+ $filename = tempnam($tempdir, "xlsx_writer_");
60
+ $this->temp_files[] = $filename;
61
+ return $filename;
62
+ }
63
+
64
+ public function writeToStdOut()
65
+ {
66
+ $temp_file = $this->tempFilename();
67
+ self::writeToFile($temp_file);
68
+ readfile($temp_file);
69
+ }
70
+
71
+ public function writeToString()
72
+ {
73
+ $temp_file = $this->tempFilename();
74
+ self::writeToFile($temp_file);
75
+ $string = file_get_contents($temp_file);
76
+ return $string;
77
+ }
78
+
79
+ public function writeToFile($filename)
80
+ {
81
+ foreach($this->sheets as $sheet_name => $sheet) {
82
+ self::finalizeSheet($sheet_name);//making sure all footers have been written
83
+ }
84
+
85
+ if ( file_exists( $filename ) ) {
86
+ if ( is_writable( $filename ) ) {
87
+ @unlink( $filename ); //if the zip already exists, remove it
88
+ } else {
89
+ self::log( "Error in " . __CLASS__ . "::" . __FUNCTION__ . ", file is not writeable." );
90
+ return;
91
+ }
92
+ }
93
+ $zip = new ZipArchive();
94
+ if (empty($this->sheets)) { self::log("Error in ".__CLASS__."::".__FUNCTION__.", no worksheets defined."); return; }
95
+ if (!$zip->open($filename, ZipArchive::CREATE)) { self::log("Error in ".__CLASS__."::".__FUNCTION__.", unable to create zip."); return; }
96
+
97
+ $zip->addEmptyDir("docProps/");
98
+ $zip->addFromString("docProps/app.xml" , self::buildAppXML() );
99
+ $zip->addFromString("docProps/core.xml", self::buildCoreXML());
100
+
101
+ $zip->addEmptyDir("_rels/");
102
+ $zip->addFromString("_rels/.rels", self::buildRelationshipsXML());
103
+
104
+ $zip->addEmptyDir("xl/worksheets/");
105
+ foreach($this->sheets as $sheet) {
106
+ $zip->addFile($sheet->filename, "xl/worksheets/".$sheet->xmlname );
107
+ }
108
+ $zip->addFromString("xl/workbook.xml" , self::buildWorkbookXML() );
109
+ $zip->addFile($this->writeStylesXML(), "xl/styles.xml" ); //$zip->addFromString("xl/styles.xml" , self::buildStylesXML() );
110
+ $zip->addFromString("[Content_Types].xml" , self::buildContentTypesXML() );
111
+
112
+ $zip->addEmptyDir("xl/_rels/");
113
+ $zip->addFromString("xl/_rels/workbook.xml.rels", self::buildWorkbookRelsXML() );
114
+ $zip->close();
115
+ }
116
+
117
+ protected function initializeSheet($sheet_name, $col_widths=array(), $auto_filter=false, $freeze_rows=false, $freeze_columns=false )
118
+ {
119
+ //if already initialized
120
+ if ($this->current_sheet==$sheet_name || isset($this->sheets[$sheet_name]))
121
+ return;
122
+
123
+ $sheet_filename = $this->tempFilename();
124
+ $sheet_xmlname = 'sheet' . (count($this->sheets) + 1).".xml";
125
+ $this->sheets[$sheet_name] = (object)array(
126
+ 'filename' => $sheet_filename,
127
+ 'sheetname' => $sheet_name,
128
+ 'xmlname' => $sheet_xmlname,
129
+ 'row_count' => 0,
130
+ 'file_writer' => new XLSXWriter_BuffererWriter($sheet_filename),
131
+ 'columns' => array(),
132
+ 'merge_cells' => array(),
133
+ 'max_cell_tag_start' => 0,
134
+ 'max_cell_tag_end' => 0,
135
+ 'auto_filter' => $auto_filter,
136
+ 'freeze_rows' => $freeze_rows,
137
+ 'freeze_columns' => $freeze_columns,
138
+ 'finalized' => false,
139
+ );
140
+ $rightToLeftValue = $this->isRightToLeft ? 'true' : 'false';
141
+ $sheet = &$this->sheets[$sheet_name];
142
+ $tabselected = count($this->sheets) == 1 ? 'true' : 'false';//only first sheet is selected
143
+ $max_cell=XLSXWriter::xlsCell(self::EXCEL_2007_MAX_ROW, self::EXCEL_2007_MAX_COL);//XFE1048577
144
+ $sheet->file_writer->write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . "\n");
145
+ $sheet->file_writer->write('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">');
146
+ $sheet->file_writer->write( '<sheetPr filterMode="false">');
147
+ $sheet->file_writer->write( '<pageSetUpPr fitToPage="false"/>');
148
+ $sheet->file_writer->write( '</sheetPr>');
149
+ $sheet->max_cell_tag_start = $sheet->file_writer->ftell();
150
+ $sheet->file_writer->write('<dimension ref="A1:' . $max_cell . '"/>');
151
+ $sheet->max_cell_tag_end = $sheet->file_writer->ftell();
152
+ $sheet->file_writer->write( '<sheetViews>');
153
+ $sheet->file_writer->write( '<sheetView colorId="64" defaultGridColor="true" rightToLeft="'.$rightToLeftValue.'" showFormulas="false" showGridLines="true" showOutlineSymbols="true" showRowColHeaders="true" showZeros="true" tabSelected="' . $tabselected . '" topLeftCell="A1" view="normal" windowProtection="false" workbookViewId="0" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100">');
154
+ if ($sheet->freeze_rows && $sheet->freeze_columns) {
155
+ $sheet->file_writer->write( '<pane ySplit="'.$sheet->freeze_rows.'" xSplit="'.$sheet->freeze_columns.'" topLeftCell="'.self::xlsCell($sheet->freeze_rows, $sheet->freeze_columns).'" activePane="bottomRight" state="frozen"/>');
156
+ $sheet->file_writer->write( '<selection activeCell="'.self::xlsCell($sheet->freeze_rows, 0).'" activeCellId="0" pane="topRight" sqref="'.self::xlsCell($sheet->freeze_rows, 0).'"/>');
157
+ $sheet->file_writer->write( '<selection activeCell="'.self::xlsCell(0, $sheet->freeze_columns).'" activeCellId="0" pane="bottomLeft" sqref="'.self::xlsCell(0, $sheet->freeze_columns).'"/>');
158
+ $sheet->file_writer->write( '<selection activeCell="'.self::xlsCell($sheet->freeze_rows, $sheet->freeze_columns).'" activeCellId="0" pane="bottomRight" sqref="'.self::xlsCell($sheet->freeze_rows, $sheet->freeze_columns).'"/>');
159
+ }
160
+ elseif ($sheet->freeze_rows) {
161
+ $sheet->file_writer->write( '<pane ySplit="'.$sheet->freeze_rows.'" topLeftCell="'.self::xlsCell($sheet->freeze_rows, 0).'" activePane="bottomLeft" state="frozen"/>');
162
+ $sheet->file_writer->write( '<selection activeCell="'.self::xlsCell($sheet->freeze_rows, 0).'" activeCellId="0" pane="bottomLeft" sqref="'.self::xlsCell($sheet->freeze_rows, 0).'"/>');
163
+ }
164
+ elseif ($sheet->freeze_columns) {
165
+ $sheet->file_writer->write( '<pane xSplit="'.$sheet->freeze_columns.'" topLeftCell="'.self::xlsCell(0, $sheet->freeze_columns).'" activePane="topRight" state="frozen"/>');
166
+ $sheet->file_writer->write( '<selection activeCell="'.self::xlsCell(0, $sheet->freeze_columns).'" activeCellId="0" pane="topRight" sqref="'.self::xlsCell(0, $sheet->freeze_columns).'"/>');
167
+ }
168
+ else { // not frozen
169
+ $sheet->file_writer->write( '<selection activeCell="A1" activeCellId="0" pane="topLeft" sqref="A1"/>');
170
+ }
171
+ $sheet->file_writer->write( '</sheetView>');
172
+ $sheet->file_writer->write( '</sheetViews>');
173
+ $sheet->file_writer->write( '<cols>');
174
+ $i=0;
175
+ if (!empty($col_widths)) {
176
+ foreach($col_widths as $column_width) {
177
+ $sheet->file_writer->write( '<col collapsed="false" hidden="false" max="'.($i+1).'" min="'.($i+1).'" style="0" customWidth="true" width="'.floatval($column_width).'"/>');
178
+ $i++;
179
+ }
180
+ }
181
+ $sheet->file_writer->write( '<col collapsed="false" hidden="false" max="1024" min="'.($i+1).'" style="0" customWidth="false" width="11.5"/>');
182
+ $sheet->file_writer->write( '</cols>');
183
+ $sheet->file_writer->write( '<sheetData>');
184
+ }
185
+
186
+ private function addCellStyle($number_format, $cell_style_string)
187
+ {
188
+ $number_format_idx = self::add_to_list_get_index($this->number_formats, $number_format);
189
+ $lookup_string = $number_format_idx.";".$cell_style_string;
190
+ $cell_style_idx = self::add_to_list_get_index($this->cell_styles, $lookup_string);
191
+ return $cell_style_idx;
192
+ }
193
+
194
+ private function initializeColumnTypes($header_types)
195
+ {
196
+ $column_types = array();
197
+ foreach($header_types as $v)
198
+ {
199
+ $number_format = self::numberFormatStandardized($v);
200
+ $number_format_type = self::determineNumberFormatType($number_format);
201
+ $cell_style_idx = $this->addCellStyle($number_format, $style_string=null);
202
+ $column_types[] = array('number_format' => $number_format,//contains excel format like 'YYYY-MM-DD HH:MM:SS'
203
+ 'number_format_type' => $number_format_type, //contains friendly format like 'datetime'
204
+ 'default_cell_style' => $cell_style_idx,
205
+ );
206
+ }
207
+ return $column_types;
208
+ }
209
+
210
+ public function writeSheetHeader($sheet_name, array $header_types, $col_options = null)
211
+ {
212
+ if (empty($sheet_name) || empty($header_types) || !empty($this->sheets[$sheet_name]))
213
+ return;
214
+
215
+ $suppress_row = isset($col_options['suppress_row']) ? intval($col_options['suppress_row']) : false;
216
+ if (is_bool($col_options))
217
+ {
218
+ self::log( "Warning! passing $suppress_row=false|true to writeSheetHeader() is deprecated, this will be removed in a future version." );
219
+ $suppress_row = intval($col_options);
220
+ }
221
+ $style = &$col_options;
222
+
223
+ $col_widths = isset($col_options['widths']) ? (array)$col_options['widths'] : array();
224
+ $auto_filter = isset($col_options['auto_filter']) ? intval($col_options['auto_filter']) : false;
225
+ $freeze_rows = isset($col_options['freeze_rows']) ? intval($col_options['freeze_rows']) : false;
226
+ $freeze_columns = isset($col_options['freeze_columns']) ? intval($col_options['freeze_columns']) : false;
227
+ self::initializeSheet($sheet_name, $col_widths, $auto_filter, $freeze_rows, $freeze_columns);
228
+ $sheet = &$this->sheets[$sheet_name];
229
+ $sheet->columns = $this->initializeColumnTypes($header_types);
230
+ if (!$suppress_row)
231
+ {
232
+ $header_row = array_keys($header_types);
233
+
234
+ $sheet->file_writer->write('<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="' . (1) . '">');
235
+ foreach ($header_row as $c => $v) {
236
+ $cell_style_idx = empty($style) ? $sheet->columns[$c]['default_cell_style'] : $this->addCellStyle( 'GENERAL', json_encode(isset($style[0]) ? $style[$c] : $style) );
237
+ $this->writeCell($sheet->file_writer, 0, $c, $v, $number_format_type='n_string', $cell_style_idx);
238
+ }
239
+ $sheet->file_writer->write('</row>');
240
+ $sheet->row_count++;
241
+ }
242
+ $this->current_sheet = $sheet_name;
243
+ }
244
+
245
+ public function writeSheetRow($sheet_name, array $row, $row_options=null)
246
+ {
247
+ if (empty($sheet_name))
248
+ return;
249
+
250
+ $this->initializeSheet($sheet_name);
251
+ $sheet = &$this->sheets[$sheet_name];
252
+ if (count($sheet->columns) < count($row)) {
253
+ $default_column_types = $this->initializeColumnTypes( array_fill($from=0, $until=count($row), 'GENERAL') );//will map to n_auto
254
+ $sheet->columns = array_merge((array)$sheet->columns, $default_column_types);
255
+ }
256
+
257
+ if (!empty($row_options))
258
+ {
259
+ $ht = isset($row_options['height']) ? floatval($row_options['height']) : 12.1;
260
+ $customHt = isset($row_options['height']) ? true : false;
261
+ $hidden = isset($row_options['hidden']) ? (bool)($row_options['hidden']) : false;
262
+ $collapsed = isset($row_options['collapsed']) ? (bool)($row_options['collapsed']) : false;
263
+ $sheet->file_writer->write('<row collapsed="'.($collapsed).'" customFormat="false" customHeight="'.($customHt).'" hidden="'.($hidden).'" ht="'.($ht).'" outlineLevel="0" r="' . ($sheet->row_count + 1) . '">');
264
+ }
265
+ else
266
+ {
267
+ $sheet->file_writer->write('<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="' . ($sheet->row_count + 1) . '">');
268
+ }
269
+
270
+ $style = &$row_options;
271
+ $c=0;
272
+ foreach ($row as $v) {
273
+ $number_format = $sheet->columns[$c]['number_format'];
274
+ $number_format_type = $sheet->columns[$c]['number_format_type'];
275
+ $cell_style_idx = empty($style) ? $sheet->columns[$c]['default_cell_style'] : $this->addCellStyle( $number_format, json_encode(isset($style[0]) ? $style[$c] : $style) );
276
+ $this->writeCell($sheet->file_writer, $sheet->row_count, $c, $v, $number_format_type, $cell_style_idx);
277
+ $c++;
278
+ }
279
+ $sheet->file_writer->write('</row>');
280
+ $sheet->row_count++;
281
+ $this->current_sheet = $sheet_name;
282
+ }
283
+
284
+ public function countSheetRows($sheet_name = '')
285
+ {
286
+ $sheet_name = $sheet_name ?: $this->current_sheet;
287
+ return array_key_exists($sheet_name, $this->sheets) ? $this->sheets[$sheet_name]->row_count : 0;
288
+ }
289
+
290
+ protected function finalizeSheet($sheet_name)
291
+ {
292
+ if (empty($sheet_name) || $this->sheets[$sheet_name]->finalized)
293
+ return;
294
+
295
+ $sheet = &$this->sheets[$sheet_name];
296
+
297
+ $sheet->file_writer->write( '</sheetData>');
298
+
299
+ if (!empty($sheet->merge_cells)) {
300
+ $sheet->file_writer->write( '<mergeCells>');
301
+ foreach ($sheet->merge_cells as $range) {
302
+ $sheet->file_writer->write( '<mergeCell ref="' . $range . '"/>');
303
+ }
304
+ $sheet->file_writer->write( '</mergeCells>');
305
+ }
306
+
307
+ $max_cell = self::xlsCell($sheet->row_count - 1, count($sheet->columns) - 1);
308
+
309
+ if ($sheet->auto_filter) {
310
+ $sheet->file_writer->write( '<autoFilter ref="A1:' . $max_cell . '"/>');
311
+ }
312
+
313
+ $sheet->file_writer->write( '<printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false" verticalCentered="false"/>');
314
+ $sheet->file_writer->write( '<pageMargins left="0.5" right="0.5" top="1.0" bottom="1.0" header="0.5" footer="0.5"/>');
315
+ $sheet->file_writer->write( '<pageSetup blackAndWhite="false" cellComments="none" copies="1" draft="false" firstPageNumber="1" fitToHeight="1" fitToWidth="1" horizontalDpi="300" orientation="portrait" pageOrder="downThenOver" paperSize="1" scale="100" useFirstPageNumber="true" usePrinterDefaults="false" verticalDpi="300"/>');
316
+ $sheet->file_writer->write( '<headerFooter differentFirst="false" differentOddEven="false">');
317
+ $sheet->file_writer->write( '<oddHeader>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12&amp;A</oddHeader>');
318
+ $sheet->file_writer->write( '<oddFooter>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12Page &amp;P</oddFooter>');
319
+ $sheet->file_writer->write( '</headerFooter>');
320
+ $sheet->file_writer->write('</worksheet>');
321
+
322
+ $max_cell_tag = '<dimension ref="A1:' . $max_cell . '"/>';
323
+ $padding_length = $sheet->max_cell_tag_end - $sheet->max_cell_tag_start - strlen($max_cell_tag);
324
+ $sheet->file_writer->fseek($sheet->max_cell_tag_start);
325
+ $sheet->file_writer->write($max_cell_tag.str_repeat(" ", $padding_length));
326
+ $sheet->file_writer->close();
327
+ $sheet->finalized=true;
328
+ }
329
+
330
+ public function markMergedCell($sheet_name, $start_cell_row, $start_cell_column, $end_cell_row, $end_cell_column)
331
+ {
332
+ if (empty($sheet_name) || $this->sheets[$sheet_name]->finalized)
333
+ return;
334
+
335
+ self::initializeSheet($sheet_name);
336
+ $sheet = &$this->sheets[$sheet_name];
337
+
338
+ $startCell = self::xlsCell($start_cell_row, $start_cell_column);
339
+ $endCell = self::xlsCell($end_cell_row, $end_cell_column);
340
+ $sheet->merge_cells[] = $startCell . ":" . $endCell;
341
+ }
342
+
343
+ public function writeSheet(array $data, $sheet_name='', array $header_types=array())
344
+ {
345
+ $sheet_name = empty($sheet_name) ? 'Sheet1' : $sheet_name;
346
+ $data = empty($data) ? array(array('')) : $data;
347
+ if (!empty($header_types))
348
+ {
349
+ $this->writeSheetHeader($sheet_name, $header_types);
350
+ }
351
+ foreach($data as $i=>$row)
352
+ {
353
+ $this->writeSheetRow($sheet_name, $row);
354
+ }
355
+ $this->finalizeSheet($sheet_name);
356
+ }
357
+
358
+ protected function writeCell(XLSXWriter_BuffererWriter &$file, $row_number, $column_number, $value, $num_format_type, $cell_style_idx)
359
+ {
360
+ $cell_name = self::xlsCell($row_number, $column_number);
361
+
362
+ if (!is_scalar($value) || $value==='') { //objects, array, empty
363
+ $file->write('<c r="'.$cell_name.'" s="'.$cell_style_idx.'"/>');
364
+ } elseif (is_string($value) && $value[0]=='='){
365
+ $file->write('<c r="'.$cell_name.'" s="'.$cell_style_idx.'" t="s"><f>'.self::xmlspecialchars($value).'</f></c>');
366
+ } elseif ($num_format_type=='n_date') {
367
+ $file->write('<c r="'.$cell_name.'" s="'.$cell_style_idx.'" t="n"><v>'.intval(self::convert_date_time($value)).'</v></c>');
368
+ } elseif ($num_format_type=='n_datetime') {
369
+ $file->write('<c r="'.$cell_name.'" s="'.$cell_style_idx.'" t="n"><v>'.self::convert_date_time($value).'</v></c>');
370
+ } elseif ($num_format_type=='n_numeric') {
371
+ $file->write('<c r="'.$cell_name.'" s="'.$cell_style_idx.'" t="n"><v>'.self::xmlspecialchars($value).'</v></c>');//int,float,currency
372
+ } elseif ($num_format_type=='n_string') {
373
+ $file->write('<c r="'.$cell_name.'" s="'.$cell_style_idx.'" t="inlineStr"><is><t>'.self::xmlspecialchars($value).'</t></is></c>');
374
+ } elseif ($num_format_type=='n_auto' || 1) { //auto-detect unknown column types
375
+ if (!is_string($value) || $value=='0' || ($value[0]!='0' && ctype_digit($value)) || preg_match("/^\-?(0|[1-9][0-9]*)(\.[0-9]+)?$/", $value)){
376
+ $file->write('<c r="'.$cell_name.'" s="'.$cell_style_idx.'" t="n"><v>'.self::xmlspecialchars($value).'</v></c>');//int,float,currency
377
+ } else { //implied: ($cell_format=='string')
378
+ $file->write('<c r="'.$cell_name.'" s="'.$cell_style_idx.'" t="inlineStr"><is><t>'.self::xmlspecialchars($value).'</t></is></c>');
379
+ }
380
+ }
381
+ }
382
+
383
+ protected function styleFontIndexes()
384
+ {
385
+ static $border_allowed = array('left','right','top','bottom');
386
+ static $border_style_allowed = array('thin','medium','thick','dashDot','dashDotDot','dashed','dotted','double','hair','mediumDashDot','mediumDashDotDot','mediumDashed','slantDashDot');
387
+ static $horizontal_allowed = array('general','left','right','justify','center');
388
+ static $vertical_allowed = array('bottom','center','distributed','top');
389
+ $default_font = array('size'=>'10','name'=>'Arial','family'=>'2');
390
+ $fills = array('','');//2 placeholders for static xml later
391
+ $fonts = array('','','','');//4 placeholders for static xml later
392
+ $borders = array('');//1 placeholder for static xml later
393
+ $style_indexes = array();
394
+ foreach($this->cell_styles as $i=>$cell_style_string)
395
+ {
396
+ $semi_colon_pos = strpos($cell_style_string,";");
397
+ $number_format_idx = substr($cell_style_string, 0, $semi_colon_pos);
398
+ $style_json_string = substr($cell_style_string, $semi_colon_pos+1);
399
+ $style = @json_decode($style_json_string, $as_assoc=true);
400
+
401
+ $style_indexes[$i] = array('num_fmt_idx'=>$number_format_idx);//initialize entry
402
+ if (isset($style['border']) && is_string($style['border']))//border is a comma delimited str
403
+ {
404
+ $border_value['side'] = array_intersect(explode(",", $style['border']), $border_allowed);
405
+ if (isset($style['border-style']) && in_array($style['border-style'],$border_style_allowed))
406
+ {
407
+ $border_value['style'] = $style['border-style'];
408
+ }
409
+ if (isset($style['border-color']) && is_string($style['border-color']) && $style['border-color'][0]=='#')
410
+ {
411
+ $v = substr($style['border-color'],1,6);
412
+ $v = strlen($v)==3 ? $v[0].$v[0].$v[1].$v[1].$v[2].$v[2] : $v;// expand cf0 => ccff00
413
+ $border_value['color'] = "FF".strtoupper($v);
414
+ }
415
+ $style_indexes[$i]['border_idx'] = self::add_to_list_get_index($borders, json_encode($border_value));
416
+ }
417
+ if (isset($style['fill']) && is_string($style['fill']) && $style['fill'][0]=='#')
418
+ {
419
+ $v = substr($style['fill'],1,6);
420
+ $v = strlen($v)==3 ? $v[0].$v[0].$v[1].$v[1].$v[2].$v[2] : $v;// expand cf0 => ccff00
421
+ $style_indexes[$i]['fill_idx'] = self::add_to_list_get_index($fills, "FF".strtoupper($v) );
422
+ }
423
+ if (isset($style['halign']) && in_array($style['halign'],$horizontal_allowed))
424
+ {
425
+ $style_indexes[$i]['alignment'] = true;
426
+ $style_indexes[$i]['halign'] = $style['halign'];
427
+ }
428
+ if (isset($style['valign']) && in_array($style['valign'],$vertical_allowed))
429
+ {
430
+ $style_indexes[$i]['alignment'] = true;
431
+ $style_indexes[$i]['valign'] = $style['valign'];
432
+ }
433
+ if (isset($style['wrap_text']))
434
+ {
435
+ $style_indexes[$i]['alignment'] = true;
436
+ $style_indexes[$i]['wrap_text'] = (bool)$style['wrap_text'];
437
+ }
438
+
439
+ $font = $default_font;
440
+ if (isset($style['font-size']))
441
+ {
442
+ $font['size'] = floatval($style['font-size']);//floatval to allow "10.5" etc
443
+ }
444
+ if (isset($style['font']) && is_string($style['font']))
445
+ {
446
+ if ($style['font']=='Comic Sans MS') { $font['family']=4; }
447
+ if ($style['font']=='Times New Roman') { $font['family']=1; }
448
+ if ($style['font']=='Courier New') { $font['family']=3; }
449
+ $font['name'] = strval($style['font']);
450
+ }
451
+ if (isset($style['font-style']) && is_string($style['font-style']))
452
+ {
453
+ if (strpos($style['font-style'], 'bold')!==false) { $font['bold'] = true; }
454
+ if (strpos($style['font-style'], 'italic')!==false) { $font['italic'] = true; }
455
+ if (strpos($style['font-style'], 'strike')!==false) { $font['strike'] = true; }
456
+ if (strpos($style['font-style'], 'underline')!==false) { $font['underline'] = true; }
457
+ }
458
+ if (isset($style['color']) && is_string($style['color']) && $style['color'][0]=='#' )
459
+ {
460
+ $v = substr($style['color'],1,6);
461
+ $v = strlen($v)==3 ? $v[0].$v[0].$v[1].$v[1].$v[2].$v[2] : $v;// expand cf0 => ccff00
462
+ $font['color'] = "FF".strtoupper($v);
463
+ }
464
+ if ($font!=$default_font)
465
+ {
466
+ $style_indexes[$i]['font_idx'] = self::add_to_list_get_index($fonts, json_encode($font) );
467
+ }
468
+ }
469
+ return array('fills'=>$fills,'fonts'=>$fonts,'borders'=>$borders,'styles'=>$style_indexes );
470
+ }
471
+
472
+ protected function writeStylesXML()
473
+ {
474
+ $r = self::styleFontIndexes();
475
+ $fills = $r['fills'];
476
+ $fonts = $r['fonts'];
477
+ $borders = $r['borders'];
478
+ $style_indexes = $r['styles'];
479
+
480
+ $temporary_filename = $this->tempFilename();
481
+ $file = new XLSXWriter_BuffererWriter($temporary_filename);
482
+ $file->write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n");
483
+ $file->write('<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">');
484
+ $file->write('<numFmts count="'.count($this->number_formats).'">');
485
+ foreach($this->number_formats as $i=>$v) {
486
+ $file->write('<numFmt numFmtId="'.(164+$i).'" formatCode="'.self::xmlspecialchars($v).'" />');
487
+ }
488
+ //$file->write( '<numFmt formatCode="GENERAL" numFmtId="164"/>');
489
+ //$file->write( '<numFmt formatCode="[$$-1009]#,##0.00;[RED]\-[$$-1009]#,##0.00" numFmtId="165"/>');
490
+ //$file->write( '<numFmt formatCode="YYYY-MM-DD\ HH:MM:SS" numFmtId="166"/>');
491
+ //$file->write( '<numFmt formatCode="YYYY-MM-DD" numFmtId="167"/>');
492
+ $file->write('</numFmts>');
493
+
494
+ $file->write('<fonts count="'.(count($fonts)).'">');
495
+ $file->write( '<font><name val="Arial"/><charset val="1"/><family val="2"/><sz val="10"/></font>');
496
+ $file->write( '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>');
497
+ $file->write( '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>');
498
+ $file->write( '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>');
499
+
500
+ foreach($fonts as $font) {
501
+ if (!empty($font)) { //fonts have 4 empty placeholders in array to offset the 4 static xml entries above
502
+ $f = json_decode($font,true);
503
+ $file->write('<font>');
504
+ $file->write( '<name val="'.htmlspecialchars($f['name']).'"/><charset val="1"/><family val="'.intval($f['family']).'"/>');
505
+ $file->write( '<sz val="'.intval($f['size']).'"/>');
506
+ if (!empty($f['color'])) { $file->write('<color rgb="'.strval($f['color']).'"/>'); }
507
+ if (!empty($f['bold'])) { $file->write('<b val="true"/>'); }
508
+ if (!empty($f['italic'])) { $file->write('<i val="true"/>'); }
509
+ if (!empty($f['underline'])) { $file->write('<u val="single"/>'); }
510
+ if (!empty($f['strike'])) { $file->write('<strike val="true"/>'); }
511
+ $file->write('</font>');
512
+ }
513
+ }
514
+ $file->write('</fonts>');
515
+
516
+ $file->write('<fills count="'.(count($fills)).'">');
517
+ $file->write( '<fill><patternFill patternType="none"/></fill>');
518
+ $file->write( '<fill><patternFill patternType="gray125"/></fill>');
519
+ foreach($fills as $fill) {
520
+ if (!empty($fill)) { //fills have 2 empty placeholders in array to offset the 2 static xml entries above
521
+ $file->write('<fill><patternFill patternType="solid"><fgColor rgb="'.strval($fill).'"/><bgColor indexed="64"/></patternFill></fill>');
522
+ }
523
+ }
524
+ $file->write('</fills>');
525
+
526
+ $file->write('<borders count="'.(count($borders)).'">');
527
+ $file->write( '<border diagonalDown="false" diagonalUp="false"><left/><right/><top/><bottom/><diagonal/></border>');
528
+ foreach($borders as $border) {
529
+ if (!empty($border)) { //fonts have an empty placeholder in the array to offset the static xml entry above
530
+ $pieces = json_decode($border,true);
531
+ $border_style = !empty($pieces['style']) ? $pieces['style'] : 'hair';
532
+ $border_color = !empty($pieces['color']) ? '<color rgb="'.strval($pieces['color']).'"/>' : '';
533
+ $file->write('<border diagonalDown="false" diagonalUp="false">');
534
+ foreach (array('left', 'right', 'top', 'bottom') as $side)
535
+ {
536
+ $show_side = in_array($side,$pieces['side']) ? true : false;
537
+ $file->write($show_side ? "<$side style=\"$border_style\">$border_color</$side>" : "<$side/>");
538
+ }
539
+ $file->write( '<diagonal/>');
540
+ $file->write('</border>');
541
+ }
542
+ }
543
+ $file->write('</borders>');
544
+
545
+ $file->write('<cellStyleXfs count="20">');
546
+ $file->write( '<xf applyAlignment="true" applyBorder="true" applyFont="true" applyProtection="true" borderId="0" fillId="0" fontId="0" numFmtId="164">');
547
+ $file->write( '<alignment horizontal="general" indent="0" shrinkToFit="false" textRotation="0" vertical="bottom" wrapText="false"/>');
548
+ $file->write( '<protection hidden="false" locked="true"/>');
549
+ $file->write( '</xf>');
550
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>');
551
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>');
552
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>');
553
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>');
554
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
555
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
556
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
557
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
558
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
559
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
560
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
561
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
562
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
563
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
564
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="43"/>');
565
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="41"/>');
566
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="44"/>');
567
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="42"/>');
568
+ $file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="9"/>');
569
+ $file->write('</cellStyleXfs>');
570
+
571
+ $file->write('<cellXfs count="'.(count($style_indexes)).'">');
572
+ //$file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="164" xfId="0"/>');
573
+ //$file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="165" xfId="0"/>');
574
+ //$file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="166" xfId="0"/>');
575
+ //$file->write( '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="167" xfId="0"/>');
576
+ foreach($style_indexes as $v)
577
+ {
578
+ $applyAlignment = isset($v['alignment']) ? 'true' : 'false';
579
+ $wrapText = !empty($v['wrap_text']) ? 'true' : 'false';
580
+ $horizAlignment = isset($v['halign']) ? $v['halign'] : 'general';
581
+ $vertAlignment = isset($v['valign']) ? $v['valign'] : 'bottom';
582
+ $applyBorder = isset($v['border_idx']) ? 'true' : 'false';
583
+ $applyFont = 'true';
584
+ $borderIdx = isset($v['border_idx']) ? intval($v['border_idx']) : 0;
585
+ $fillIdx = isset($v['fill_idx']) ? intval($v['fill_idx']) : 0;
586
+ $fontIdx = isset($v['font_idx']) ? intval($v['font_idx']) : 0;
587
+ //$file->write('<xf applyAlignment="'.$applyAlignment.'" applyBorder="'.$applyBorder.'" applyFont="'.$applyFont.'" applyProtection="false" borderId="'.($borderIdx).'" fillId="'.($fillIdx).'" fontId="'.($fontIdx).'" numFmtId="'.(164+$v['num_fmt_idx']).'" xfId="0"/>');
588
+ $file->write('<xf applyAlignment="'.$applyAlignment.'" applyBorder="'.$applyBorder.'" applyFont="'.$applyFont.'" applyProtection="false" borderId="'.($borderIdx).'" fillId="'.($fillIdx).'" fontId="'.($fontIdx).'" numFmtId="'.(164+$v['num_fmt_idx']).'" xfId="0">');
589
+ $file->write(' <alignment horizontal="'.$horizAlignment.'" vertical="'.$vertAlignment.'" textRotation="0" wrapText="'.$wrapText.'" indent="0" shrinkToFit="false"/>');
590
+ $file->write(' <protection locked="true" hidden="false"/>');
591
+ $file->write('</xf>');
592
+ }
593
+ $file->write('</cellXfs>');
594
+ $file->write( '<cellStyles count="6">');
595
+ $file->write( '<cellStyle builtinId="0" customBuiltin="false" name="Normal" xfId="0"/>');
596
+ $file->write( '<cellStyle builtinId="3" customBuiltin="false" name="Comma" xfId="15"/>');
597
+ $file->write( '<cellStyle builtinId="6" customBuiltin="false" name="Comma [0]" xfId="16"/>');
598
+ $file->write( '<cellStyle builtinId="4" customBuiltin="false" name="Currency" xfId="17"/>');
599
+ $file->write( '<cellStyle builtinId="7" customBuiltin="false" name="Currency [0]" xfId="18"/>');
600
+ $file->write( '<cellStyle builtinId="5" customBuiltin="false" name="Percent" xfId="19"/>');
601
+ $file->write( '</cellStyles>');
602
+ $file->write('</styleSheet>');
603
+ $file->close();
604
+ return $temporary_filename;
605
+ }
606
+
607
+ protected function buildAppXML()
608
+ {
609
+ $app_xml="";
610
+ $app_xml.='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n";
611
+ $app_xml.='<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">';
612
+ $app_xml.='<TotalTime>0</TotalTime>';
613
+ $app_xml.='<Company>'.self::xmlspecialchars($this->company).'</Company>';
614
+ $app_xml.='</Properties>';
615
+ return $app_xml;
616
+ }
617
+
618
+ protected function buildCoreXML()
619
+ {
620
+ $core_xml="";
621
+ $core_xml.='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n";
622
+ $core_xml.='<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
623
+ $core_xml.='<dcterms:created xsi:type="dcterms:W3CDTF">'.date("Y-m-d\TH:i:s.00\Z").'</dcterms:created>';//$date_time = '2014-10-25T15:54:37.00Z';
624
+ $core_xml.='<dc:title>'.self::xmlspecialchars($this->title).'</dc:title>';
625
+ $core_xml.='<dc:subject>'.self::xmlspecialchars($this->subject).'</dc:subject>';
626
+ $core_xml.='<dc:creator>'.self::xmlspecialchars($this->author).'</dc:creator>';
627
+ if (!empty($this->keywords)) {
628
+ $core_xml.='<cp:keywords>'.self::xmlspecialchars(implode (", ", (array)$this->keywords)).'</cp:keywords>';
629
+ }
630
+ $core_xml.='<dc:description>'.self::xmlspecialchars($this->description).'</dc:description>';
631
+ $core_xml.='<cp:revision>0</cp:revision>';
632
+ $core_xml.='</cp:coreProperties>';
633
+ return $core_xml;
634
+ }
635
+
636
+ protected function buildRelationshipsXML()
637
+ {
638
+ $rels_xml="";
639
+ $rels_xml.='<?xml version="1.0" encoding="UTF-8"?>'."\n";
640
+ $rels_xml.='<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">';
641
+ $rels_xml.='<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>';
642
+ $rels_xml.='<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>';
643
+ $rels_xml.='<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>';
644
+ $rels_xml.="\n";
645
+ $rels_xml.='</Relationships>';
646
+ return $rels_xml;
647
+ }
648
+
649
+ protected function buildWorkbookXML()
650
+ {
651
+ $i=0;
652
+ $workbook_xml="";
653
+ $workbook_xml.='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n";
654
+ $workbook_xml.='<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">';
655
+ $workbook_xml.='<fileVersion appName="Calc"/><workbookPr backupFile="false" showObjects="all" date1904="false"/><workbookProtection/>';
656
+ $workbook_xml.='<bookViews><workbookView activeTab="0" firstSheet="0" showHorizontalScroll="true" showSheetTabs="true" showVerticalScroll="true" tabRatio="212" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"/></bookViews>';
657
+ $workbook_xml.='<sheets>';
658
+ foreach($this->sheets as $sheet_name=>$sheet) {
659
+ $sheetname = self::sanitize_sheetname($sheet->sheetname);
660
+ $workbook_xml.='<sheet name="'.self::xmlspecialchars($sheetname).'" sheetId="'.($i+1).'" state="visible" r:id="rId'.($i+2).'"/>';
661
+ $i++;
662
+ }
663
+ $workbook_xml.='</sheets>';
664
+ $workbook_xml.='<definedNames>';
665
+ foreach($this->sheets as $sheet_name=>$sheet) {
666
+ if ($sheet->auto_filter) {
667
+ $sheetname = self::sanitize_sheetname($sheet->sheetname);
668
+ $workbook_xml.='<definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">\''.self::xmlspecialchars($sheetname).'\'!$A$1:' . self::xlsCell($sheet->row_count - 1, count($sheet->columns) - 1, true) . '</definedName>';
669
+ $i++;
670
+ }
671
+ }
672
+ $workbook_xml.='</definedNames>';
673
+ $workbook_xml.='<calcPr iterateCount="100" refMode="A1" iterate="false" iterateDelta="0.001"/></workbook>';
674
+ return $workbook_xml;
675
+ }
676
+
677
+ protected function buildWorkbookRelsXML()
678
+ {
679
+ $i=0;
680
+ $wkbkrels_xml="";
681
+ $wkbkrels_xml.='<?xml version="1.0" encoding="UTF-8"?>'."\n";
682
+ $wkbkrels_xml.='<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">';
683
+ $wkbkrels_xml.='<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>';
684
+ foreach($this->sheets as $sheet_name=>$sheet) {
685
+ $wkbkrels_xml.='<Relationship Id="rId'.($i+2).'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/'.($sheet->xmlname).'"/>';
686
+ $i++;
687
+ }
688
+ $wkbkrels_xml.="\n";
689
+ $wkbkrels_xml.='</Relationships>';
690
+ return $wkbkrels_xml;
691
+ }
692
+
693
+ protected function buildContentTypesXML()
694
+ {
695
+ $content_types_xml="";
696
+ $content_types_xml.='<?xml version="1.0" encoding="UTF-8"?>'."\n";
697
+ $content_types_xml.='<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">';
698
+ $content_types_xml.='<Override PartName="/_rels/.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>';
699
+ $content_types_xml.='<Override PartName="/xl/_rels/workbook.xml.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>';
700
+ foreach($this->sheets as $sheet_name=>$sheet) {
701
+ $content_types_xml.='<Override PartName="/xl/worksheets/'.($sheet->xmlname).'" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>';
702
+ }
703
+ $content_types_xml.='<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>';
704
+ $content_types_xml.='<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>';
705
+ $content_types_xml.='<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>';
706
+ $content_types_xml.='<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>';
707
+ $content_types_xml.="\n";
708
+ $content_types_xml.='</Types>';
709
+ return $content_types_xml;
710
+ }
711
+
712
+ //------------------------------------------------------------------
713
+ /*
714
+ * @param $row_number int, zero based
715
+ * @param $column_number int, zero based
716
+ * @param $absolute bool
717
+ * @return Cell label/coordinates, ex: A1, C3, AA42 (or if $absolute==true: $A$1, $C$3, $AA$42)
718
+ * */
719
+ public static function xlsCell($row_number, $column_number, $absolute=false)
720
+ {
721
+ $n = $column_number;
722
+ for($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
723
+ $r = chr($n%26 + 0x41) . $r;
724
+ }
725
+ if ($absolute) {
726
+ return '$' . $r . '$' . ($row_number+1);
727
+ }
728
+ return $r . ($row_number+1);
729
+ }
730
+ //------------------------------------------------------------------
731
+ public static function log($string)
732
+ {
733
+ //file_put_contents("php://stderr", date("Y-m-d H:i:s:").rtrim(is_array($string) ? json_encode($string) : $string)."\n");
734
+ error_log(date("Y-m-d H:i:s:").rtrim(is_array($string) ? json_encode($string) : $string)."\n");
735
+ }
736
+ //------------------------------------------------------------------
737
+ public static function sanitize_filename($filename) //http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx
738
+ {
739
+ $nonprinting = array_map('chr', range(0,31));
740
+ $invalid_chars = array('<', '>', '?', '"', ':', '|', '\\', '/', '*', '&');
741
+ $all_invalids = array_merge($nonprinting,$invalid_chars);
742
+ return str_replace($all_invalids, "", $filename);
743
+ }
744
+ //------------------------------------------------------------------
745
+ public static function sanitize_sheetname($sheetname)
746
+ {
747
+ static $badchars = '\\/?*:[]';
748
+ static $goodchars = ' ';
749
+ $sheetname = strtr($sheetname, $badchars, $goodchars);
750
+ $sheetname = function_exists('mb_substr') ? mb_substr($sheetname, 0, 31) : substr($sheetname, 0, 31);
751
+ $sheetname = trim(trim(trim($sheetname),"'"));//trim before and after trimming single quotes
752
+ return !empty($sheetname) ? $sheetname : 'Sheet'.((rand()%900)+100);
753
+ }
754
+ //------------------------------------------------------------------
755
+ public static function xmlspecialchars($val)
756
+ {
757
+ //note, badchars does not include \t\n\r (\x09\x0a\x0d)
758
+ static $badchars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f";
759
+ static $goodchars = " ";
760
+ return strtr(htmlspecialchars($val, ENT_QUOTES | ENT_XML1), $badchars, $goodchars);//strtr appears to be faster than str_replace
761
+ }
762
+ //------------------------------------------------------------------
763
+ public static function array_first_key(array $arr)
764
+ {
765
+ reset($arr);
766
+ $first_key = key($arr);
767
+ return $first_key;
768
+ }
769
+ //------------------------------------------------------------------
770
+ private static function determineNumberFormatType($num_format)
771
+ {
772
+ $num_format = preg_replace("/\[(Black|Blue|Cyan|Green|Magenta|Red|White|Yellow)\]/i", "", $num_format);
773
+ if ($num_format=='GENERAL') return 'n_auto';
774
+ if ($num_format=='@') return 'n_string';
775
+ if ($num_format=='0') return 'n_numeric';
776
+ if (preg_match('/[H]{1,2}:[M]{1,2}(?![^"]*+")/i', $num_format)) return 'n_datetime';
777
+ if (preg_match('/[M]{1,2}:[S]{1,2}(?![^"]*+")/i', $num_format)) return 'n_datetime';
778
+ if (preg_match('/[Y]{2,4}(?![^"]*+")/i', $num_format)) return 'n_date';
779
+ if (preg_match('/[D]{1,2}(?![^"]*+")/i', $num_format)) return 'n_date';
780
+ if (preg_match('/[M]{1,2}(?![^"]*+")/i', $num_format)) return 'n_date';
781
+ if (preg_match('/$(?![^"]*+")/', $num_format)) return 'n_numeric';
782
+ if (preg_match('/%(?![^"]*+")/', $num_format)) return 'n_numeric';
783
+ if (preg_match('/0(?![^"]*+")/', $num_format)) return 'n_numeric';
784
+ return 'n_auto';
785
+ }
786
+ //------------------------------------------------------------------
787
+ private static function numberFormatStandardized($num_format)
788
+ {
789
+ if ($num_format=='money') { $num_format='dollar'; }
790
+ if ($num_format=='number') { $num_format='integer'; }
791
+
792
+ if ($num_format=='string') $num_format='@';
793
+ else if ($num_format=='integer') $num_format='0';
794
+ else if ($num_format=='date') $num_format='YYYY-MM-DD';
795
+ else if ($num_format=='datetime') $num_format='YYYY-MM-DD HH:MM:SS';
796
+ else if ($num_format=='time') $num_format='HH:MM:SS';
797
+ else if ($num_format=='price') $num_format='#,##0.00';
798
+ else if ($num_format=='dollar') $num_format='[$$-1009]#,##0.00;[RED]-[$$-1009]#,##0.00';
799
+ else if ($num_format=='euro') $num_format='#,##0.00 [$€-407];[RED]-#,##0.00 [$€-407]';
800
+ $ignore_until='';
801
+ $escaped = '';
802
+ for($i=0,$ix=strlen($num_format); $i<$ix; $i++)
803
+ {
804
+ $c = $num_format[$i];
805
+ if ($ignore_until=='' && $c=='[')
806
+ $ignore_until=']';
807
+ else if ($ignore_until=='' && $c=='"')
808
+ $ignore_until='"';
809
+ else if ($ignore_until==$c)
810
+ $ignore_until='';
811
+ if ($ignore_until=='' && ($c==' ' || $c=='-' || $c=='(' || $c==')') && ($i==0 || $num_format[$i-1]!='_'))
812
+ $escaped.= "\\".$c;
813
+ else
814
+ $escaped.= $c;
815
+ }
816
+ return $escaped;
817
+ }
818
+ //------------------------------------------------------------------
819
+ public static function add_to_list_get_index(&$haystack, $needle)
820
+ {
821
+ $existing_idx = array_search($needle, $haystack, $strict=true);
822
+ if ($existing_idx===false)
823
+ {
824
+ $existing_idx = count($haystack);
825
+ $haystack[] = $needle;
826
+ }
827
+ return $existing_idx;
828
+ }
829
+ //------------------------------------------------------------------
830
+ public static function convert_date_time($date_input) //thanks to Excel::Writer::XLSX::Worksheet.pm (perl)
831
+ {
832
+ $days = 0; # Number of days since epoch
833
+ $seconds = 0; # Time expressed as fraction of 24h hours in seconds
834
+ $year=$month=$day=0;
835
+ $hour=$min =$sec=0;
836
+
837
+ $date_time = $date_input;
838
+ if (preg_match("/(\d{4})\-(\d{2})\-(\d{2})/", $date_time, $matches))
839
+ {
840
+ list($junk,$year,$month,$day) = $matches;
841
+ }
842
+ if (preg_match("/(\d+):(\d{2}):(\d{2})/", $date_time, $matches))
843
+ {
844
+ list($junk,$hour,$min,$sec) = $matches;
845
+ $seconds = ( $hour * 60 * 60 + $min * 60 + $sec ) / ( 24 * 60 * 60 );
846
+ }
847
+
848
+ //using 1900 as epoch, not 1904, ignoring 1904 special case
849
+
850
+ # Special cases for Excel.
851
+ if ("$year-$month-$day"=='1899-12-31') return $seconds ; # Excel 1900 epoch
852
+ if ("$year-$month-$day"=='1900-01-00') return $seconds ; # Excel 1900 epoch
853
+ if ("$year-$month-$day"=='1900-02-29') return 60 + $seconds ; # Excel false leapday
854
+
855
+ # We calculate the date by calculating the number of days since the epoch
856
+ # and adjust for the number of leap days. We calculate the number of leap
857
+ # days by normalising the year in relation to the epoch. Thus the year 2000
858
+ # becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
859
+ $epoch = 1900;
860
+ $offset = 0;
861
+ $norm = 300;
862
+ $range = $year - $epoch;
863
+
864
+ # Set month days and check for leap year.
865
+ $leap = (($year % 400 == 0) || (($year % 4 == 0) && ($year % 100)) ) ? 1 : 0;
866
+ $mdays = array( 31, ($leap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
867
+
868
+ # Some boundary checks
869
+ if ($year!=0 || $month !=0 || $day!=0)
870
+ {
871
+ if($year < $epoch || $year > 9999) return 0;
872
+ if($month < 1 || $month > 12) return 0;
873
+ if($day < 1 || $day > $mdays[ $month - 1 ]) return 0;
874
+ }
875
+
876
+ # Accumulate the number of days since the epoch.
877
+ $days = $day; # Add days for current month
878
+ $days += array_sum( array_slice($mdays, 0, $month-1 ) ); # Add days for past months
879
+ $days += $range * 365; # Add days for past years
880
+ $days += intval( ( $range ) / 4 ); # Add leapdays
881
+ $days -= intval( ( $range + $offset ) / 100 ); # Subtract 100 year leapdays
882
+ $days += intval( ( $range + $offset + $norm ) / 400 ); # Add 400 year leapdays
883
+ $days -= $leap; # Already counted above
884
+
885
+ # Adjust for Excel erroneously treating 1900 as a leap year.
886
+ if ($days > 59) { $days++;}
887
+
888
+ return $days + $seconds;
889
+ }
890
+ //------------------------------------------------------------------
891
+ }
892
+
893
+ class XLSXWriter_BuffererWriter
894
+ {
895
+ protected $fd=null;
896
+ protected $buffer='';
897
+ protected $check_utf8=false;
898
+
899
+ public function __construct($filename, $fd_fopen_flags='w', $check_utf8=false)
900
+ {
901
+ $this->check_utf8 = $check_utf8;
902
+ $this->fd = fopen($filename, $fd_fopen_flags);
903
+ if ($this->fd===false) {
904
+ XLSXWriter::log("Unable to open $filename for writing.");
905
+ }
906
+ }
907
+
908
+ public function write($string)
909
+ {
910
+ $this->buffer.=$string;
911
+ if (isset($this->buffer[8191])) {
912
+ $this->purge();
913
+ }
914
+ }
915
+
916
+ protected function purge()
917
+ {
918
+ if ($this->fd) {
919
+ if ($this->check_utf8 && !self::isValidUTF8($this->buffer)) {
920
+ XLSXWriter::log("Error, invalid UTF8 encoding detected.");
921
+ $this->check_utf8 = false;
922
+ }
923
+ fwrite($this->fd, $this->buffer);
924
+ $this->buffer='';
925
+ }
926
+ }
927
+
928
+ public function close()
929
+ {
930
+ $this->purge();
931
+ if ($this->fd) {
932
+ fclose($this->fd);
933
+ $this->fd=null;
934
+ }
935
+ }
936
+
937
+ public function __destruct()
938
+ {
939
+ $this->close();
940
+ }
941
+
942
+ public function ftell()
943
+ {
944
+ if ($this->fd) {
945
+ $this->purge();
946
+ return ftell($this->fd);
947
+ }
948
+ return -1;
949
+ }
950
+
951
+ public function fseek($pos)
952
+ {
953
+ if ($this->fd) {
954
+ $this->purge();
955
+ return fseek($this->fd, $pos);
956
+ }
957
+ return -1;
958
+ }
959
+
960
+ protected static function isValidUTF8($string)
961
+ {
962
+ if (function_exists('mb_check_encoding'))
963
+ {
964
+ return mb_check_encoding($string, 'UTF-8') ? true : false;
965
+ }
966
+ return preg_match("//u", $string) ? true : false;
967
+ }
968
+ }
969
+
970
+
971
+
972
+ // vim: set filetype=php expandtab tabstop=4 shiftwidth=4 autoindent smartindent: