├── CHANGELOG.md ├── README.md ├── acp ├── main_info.php └── main_module.php ├── ad └── manager.php ├── adm └── style │ ├── datetimepicker │ ├── MIT-LICENSE.txt │ ├── jquery.datetimepicker.css │ ├── jquery.datetimepicker.full.js │ ├── jquery.datetimepicker.full.min.js │ └── jquery.datetimepicker.min.css │ ├── event │ └── acp_overall_footer_after.html │ ├── manage_ads.html │ └── settings_ads.html ├── analyser ├── manager.php └── test │ ├── alert.php │ ├── location_href.php │ ├── script_without_async.php │ ├── test_interface.php │ └── untrusted_connection.php ├── banner └── banner.php ├── composer.json ├── config ├── analyser.yml ├── location.yml ├── routing.yml ├── services.yml └── tables.yml ├── controller ├── admin_controller.php ├── admin_input.php ├── helper.php ├── increment_controller.php ├── ucp_controller.php └── visual_demo_controller.php ├── event └── main_listener.php ├── ext.php ├── language └── en │ ├── acp.php │ ├── common.php │ ├── info_acp_phpbb_ads.php │ ├── info_ucp_phpbb_ads.php │ ├── permissions_ads.php │ └── ucp.php ├── license.txt ├── location ├── manager.php └── type │ ├── above_footer.php │ ├── above_header.php │ ├── after_first_post.php │ ├── after_footer_navbar.php │ ├── after_header_navbar.php │ ├── after_not_first_post.php │ ├── after_posts.php │ ├── after_profile.php │ ├── after_quickreply.php │ ├── base.php │ ├── before_posts.php │ ├── before_profile.php │ ├── before_quickreply.php │ ├── below_footer.php │ ├── below_header.php │ ├── pop_up.php │ ├── scripts.php │ ├── slide_up.php │ └── type_interface.php ├── migrations ├── v10x │ ├── m10_ad_owner_schema.php │ ├── m11_ad_owner_data.php │ ├── m12_u_phpbb_ads_permission.php │ ├── m13_content_only.php │ ├── m1_initial_schema.php │ ├── m2_acp_module.php │ ├── m3_template_locations_schema.php │ ├── m4_indexes.php │ ├── m5_end_date.php │ ├── m6_hide_for_group.php │ ├── m7_adblocker.php │ ├── m8_priority.php │ └── m9_views_clicks.php └── v20x │ ├── m1_hide_ad_for_group.php │ ├── m2_centering_option.php │ ├── m3_add_start_date.php │ └── m4_admin_permission.php ├── package-lock.json ├── package.json ├── styles ├── all │ ├── template │ │ ├── event │ │ │ ├── memberlist_view_content_append.html │ │ │ ├── memberlist_view_content_prepend.html │ │ │ ├── overall_footer_after.html │ │ │ ├── overall_footer_body_after.html │ │ │ ├── overall_footer_copyright_prepend.html │ │ │ ├── overall_footer_page_body_after.html │ │ │ ├── overall_header_body_before.html │ │ │ ├── overall_header_content_before.html │ │ │ ├── overall_header_navbar_before.html │ │ │ ├── overall_header_page_body_before.html │ │ │ ├── overall_header_stylesheets_after.html │ │ │ ├── quickreply_editor_panel_after.html │ │ │ ├── quickreply_editor_panel_before.html │ │ │ ├── viewtopic_body_poll_after.html │ │ │ ├── viewtopic_body_postrow_post_after.html │ │ │ └── viewtopic_body_topic_actions_before.html │ │ ├── includes │ │ │ ├── ad_blocker.html │ │ │ ├── ad_clicks.html │ │ │ ├── ad_views.html │ │ │ ├── ad_visual_demo_notice.html │ │ │ ├── phpbb_ads_pop_up.html │ │ │ └── phpbb_ads_slide_up.html │ │ ├── js │ │ │ ├── bundle.umd.js │ │ │ └── clicks.js │ │ └── phpbb_ads_macro.html │ └── theme │ │ └── phpbbads.css ├── prosilver │ └── template │ │ └── ucp_ads_stats.html └── scaffoldBB │ └── template │ └── ucp_ads_stats.html └── ucp ├── main_info.php └── main_module.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ### 3.0.0 - 2022-06-18 4 | 5 | - Dropped support for phpBB 3.2.x (new minimum requirements: phpBB 3.3.2 and PHP 7.1.3). 6 | - Added new Admin permissions for accessing the ad management and settings. 7 | - Fixed an issue where ad blocker warning message was on top of the Quick links drop down menu. 8 | - Support for ScaffoldBB style added. 9 | 10 | ### 2.0.6 - 2022-02-22 11 | 12 | - Added an option for more aggressive handling of ad block users, requiring them to disable ad blockers to access the forum. 13 | - Switched to a stronger ad block detection script based on BlockAdBlock. 14 | - Add ADM pages to the non-content page restriction filter (to prevent showing ads during ACP login). 15 | - Fix: Prevent session ID from blocking click and view tracking. 16 | 17 | ### 2.0.5 - 2021-06-15 18 | 19 | - Updated and improved the appearance of the Visual Demo of Ad Locations. 20 | - Updated and improved ad block detection. 21 | - Improved (for hi-res displays) the appearance of the edit/delete icons in the ACP. 22 | - Fixed various typos. 23 | 24 | ### 2.0.4 - 2021-01-21 25 | 26 | - Feature: Added new advertisement locations before and after the Quick Reply editor. 27 | - Fix: Title of the popup advertisement window will be properly displayed. 28 | - Fix: Addressed potential PHP 8 compatibility issues. 29 | - Fix: Correctly handle advertisement priority in MSSQL and Oracle databases. 30 | 31 | ### 2.0.3 - 2019-12-03 32 | 33 | - Fix: Updated the "Display on content pages only" option so ads will no longer appear when writing posts or viewing member lists. This is to improve compliance with rules from Google AdSense. 34 | - Fix: Addressed an issue where ad previews in the ACP could be hidden if your browser has Ad Blocking software. 35 | - Fix: Addressed an issue when previewing an ad and any selected groups in the "Hide advertisement for groups" field would be lost. 36 | - Fix: Minor code improvements and corrections. 37 | 38 | ### 2.0.2 - 2019-04-01 39 | 40 | - Feature: Added a starting date option for advertisements. 41 | - Fix: Addressed a caching issue related to users being moved in/out of groups and not seeing the correct ads immediately for their group status. 42 | 43 | ### 2.0.1 - 2018-09-17 44 | 45 | - Feature: Added a new "Special" location we call "Scripts" which can be used for adding specialised Javascript codes like AdSense Auto ads and tracking codes. 46 | 47 | ### 2.0.0 - 2018-06-28 48 | 49 | - Feature: Added an option for automatically centering an ad. Enable this option to have an ad be centered, or disable it and use your own positioning CSS in your ad code. 50 | - Feature: Hiding ads from user groups is now set individually for each ad instead of globally. When upgrading from older versions, the old "Hide advertisement for groups" setting will be applied to all existing ads. 51 | - Fix: Restyled the visual ad locations demo. 52 | - Fix: Addressed minor code issues. 53 | 54 | ### 1.0.5 - 2018-03-06 55 | 56 | - Feature: Added a new option to display ads on content pages only. When enabled, the ad will not be shown on the UCP, MCP, Registration and Profile pages. This will help comply with certain rules, such as Google AdSense which does not allow their ads to be shown on such pages. 57 | - Feature: Ad locations option has improved organisation to make it easier to pick the appropriate location. Also, a new Visual Demo has been added, so you can see where all the ad locations physically appear on your board. 58 | - Fix: My Advertisements tab in the UCP will no longer be shown to all users, and will only be visible to advertisement owners. 59 | - Fix: Resolved an issue affecting some users where multiple ads assigned to the same location were not being randomly rotated. 60 | - Fix: Ads assigned to display after first post will only be visible now if there are replies after the first post. 61 | 62 | ### 1.0.4 - 2017-12-23 63 | 64 | - Fix: Improve handling of responsive advertisements. 65 | - Fix: Added additional statistics to the "My advertisements" tab, including expiration info and active/inactive status. 66 | 67 | ### 1.0.3 - 2017-11-19 68 | 69 | - Update: UCP Advertisements page shows more information about your ads including click/view limits, expiration date and active status of the ad. 70 | - Fix: Improve handling of Google's responsive ads and possibly other responsive ad content. 71 | 72 | ### 1.0.2 - 2017-08-20 73 | 74 | - Feature: Added more advertisement placement locations, including interactive Pop-Up and Slide-Up types. 75 | - Feature: Ad analyser can scan your Ad Code and test it for possibly dangerous or untrusted code. 76 | - Fix: More precise ad view tracking will better ignore unwanted views from bots and crawlers. 77 | - Fix: Renamed page routes should prevent ad-blockers from stopping ad view/click tracking. 78 | - Fix: Solved an issue when previewing ad in Chrome is blocked by ERR_BLOCKED_BY_XSS_AUDITOR. 79 | - Loads of code fixes and improvements. 80 | 81 | ### 1.0.1 - 2017-07-28 82 | 83 | - Feature: Advertisement views and clicks statistics. 84 | - Feature: Ad owner - a user can be designated as an ad owner and can view ad statistics. 85 | - Feature: Banner image uploading added to the ACP advertisement creation form. 86 | - Code fixes and improvements. 87 | 88 | ### 1.0.0 - 2017-06-24 89 | 90 | - First release 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advertisement Management 2 | 3 | This is the repository for the development of the Advertisement Management extension, a Google Summer of Code project developed by Jakub Senko for phpBB. 4 | 5 | [![Build Status](https://github.com/phpbb-extensions/ad-management/actions/workflows/tests.yml/badge.svg)](https://github.com/phpbb-extensions/ad-management/actions) 6 | [![codecov](https://codecov.io/gh/phpbb-extensions/ad-management/branch/master/graph/badge.svg?token=ezeD03g3Lt)](https://codecov.io/gh/phpbb-extensions/ad-management) 7 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/phpbb-extensions/ad-management/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/phpbb-extensions/ad-management/?branch=master) 8 | 9 | The Advertisement Management extension allows phpBB board administrators to add and manage advertisements on their forums. Features include: 10 | 11 | - Create unlimited advertisements. Accepts code snippets (such as Google AdSense) or create your own HTML/JS ads. Add, edit, preview, disable, delete and banner image upload functionality in the Admin Control Panel. 12 | - Display ads in a variety of locations and techniques (inline, pop-up, slide-up). 13 | - Set ad priority to display important ads more often than others. 14 | - Statistics: ad views and clicks can be counted. 15 | - Option to assign an ad owner who can monitor their ad’s statistics. 16 | - Option to expire ads after reaching a certain date or number of clicks and/or views. 17 | - Option to hide ads for specific member group(s). 18 | - Ad-Blocker detection option politely notifies users to disable ad blocking on the board. 19 | - Ad code analysis can check for troublesome code such as JS alert() or making HTTP requests from a secure server. 20 | 21 | 📦 [Download](https://www.phpbb.com/customise/db/extension/ads/) the latest release of this extension. 22 | 23 | 🐞 [Report bugs](https://github.com/phpbb-extensions/ad-management/issues) to our Issue Tracker. 24 | 25 | 💬 [Support](https://www.phpbb.com/customise/db/extension/ads/support) can be requested and discussed in the Advertisement Management support forum at phpBB.com. 26 | 27 | ## License 28 | 29 | [GNU General Public License v2](license.txt) 30 | -------------------------------------------------------------------------------- /acp/main_info.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\acp; 12 | 13 | /** 14 | * Advertisement management ACP module info. 15 | */ 16 | class main_info 17 | { 18 | public function module() 19 | { 20 | return array( 21 | 'filename' => '\phpbb\ads\acp\main_module', 22 | 'title' => 'ACP_PHPBB_ADS_TITLE', 23 | 'modes' => array( 24 | 'manage' => array( 25 | 'title' => 'ACP_MANAGE_ADS_TITLE', 26 | 'auth' => 'ext_phpbb/ads && acl_a_phpbb_ads_m', 27 | 'cat' => array('ACP_PHPBB_ADS_TITLE') 28 | ), 29 | 'settings' => array( 30 | 'title' => 'ACP_ADS_SETTINGS_TITLE', 31 | 'auth' => 'ext_phpbb/ads && acl_a_phpbb_ads_s', 32 | 'cat' => array('ACP_PHPBB_ADS_TITLE') 33 | ), 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /acp/main_module.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\acp; 12 | 13 | /** 14 | * Advertisement management ACP module. 15 | */ 16 | class main_module 17 | { 18 | public $page_title; 19 | public $tpl_name; 20 | public $u_action; 21 | 22 | /** 23 | * Main ACP module 24 | * 25 | * @param int $id 26 | * @param string $mode 27 | * @throws \Exception 28 | */ 29 | public function main($id, $mode) 30 | { 31 | global $phpbb_container; 32 | 33 | /** @var \phpbb\ads\controller\admin_controller $admin_controller */ 34 | $admin_controller = $phpbb_container->get('phpbb.ads.admin.controller'); 35 | 36 | // Make the $u_action url available in the admin controller 37 | $admin_controller->set_page_url($this->u_action); 38 | 39 | // Load a template from adm/style for our ACP page 40 | $this->tpl_name = $mode . '_ads'; 41 | 42 | // Set the page title for our ACP page 43 | $this->page_title = 'ACP_PHPBB_ADS_TITLE'; 44 | 45 | $admin_controller->{'mode_' . $mode}(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ad/manager.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\ad; 12 | 13 | class manager 14 | { 15 | /** @var \phpbb\db\driver\driver_interface */ 16 | protected $db; 17 | 18 | /** @var \phpbb\config\config */ 19 | protected $config; 20 | 21 | /** @var string */ 22 | protected $ads_table; 23 | 24 | /** @var string */ 25 | protected $ad_locations_table; 26 | 27 | /** @var string */ 28 | protected $ad_group_table; 29 | 30 | /** 31 | * Constructor 32 | * 33 | * @param \phpbb\db\driver\driver_interface $db DB driver interface 34 | * @param \phpbb\config\config $config Config object 35 | * @param string $ads_table Ads table 36 | * @param string $ad_locations_table Ad locations table 37 | * @param string $ad_group_table Ad group table 38 | */ 39 | public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, $ads_table, $ad_locations_table, $ad_group_table) 40 | { 41 | $this->db = $db; 42 | $this->config = $config; 43 | $this->ads_table = $ads_table; 44 | $this->ad_locations_table = $ad_locations_table; 45 | $this->ad_group_table = $ad_group_table; 46 | } 47 | 48 | /** 49 | * Get specific ad 50 | * 51 | * @param int $ad_id Advertisement ID 52 | * @return array Array with advertisement data 53 | */ 54 | public function get_ad($ad_id) 55 | { 56 | $sql = 'SELECT * 57 | FROM ' . $this->ads_table . ' 58 | WHERE ad_id = ' . (int) $ad_id; 59 | $result = $this->db->sql_query($sql); 60 | $data = $this->db->sql_fetchrow($result); 61 | $this->db->sql_freeresult($result); 62 | 63 | return $data !== false ? $data : []; 64 | } 65 | 66 | /** 67 | * Get one ad per every location 68 | * 69 | * @param array $ad_locations List of ad locations to fetch ads for 70 | * @param array $user_groups List of user groups 71 | * @param bool $non_content_page Is current page non-content oriented (e.g.: login, UCP, MCP)? Default is false. 72 | * @return array List of ad codes for each location 73 | */ 74 | public function get_ads($ad_locations, $user_groups, $non_content_page = false) 75 | { 76 | $sql_where_views = $this->config['phpbb_ads_enable_views'] ? 'AND (a.ad_views_limit = 0 OR a.ad_views_limit > a.ad_views)' : ''; 77 | $sql_where_clicks = $this->config['phpbb_ads_enable_clicks'] ? 'AND (a.ad_clicks_limit = 0 OR a.ad_clicks_limit > a.ad_clicks)' : ''; 78 | $sql_where_non_content = $non_content_page ? 'AND a.ad_content_only = 0' : ''; 79 | $sql_where_user_groups = !empty($user_groups) ? 'AND NOT EXISTS (SELECT ag.group_id FROM ' . $this->ad_group_table . ' ag WHERE ag.ad_id = a.ad_id AND ' . $this->db->sql_in_set('ag.group_id', $user_groups) . ')' : ''; 80 | 81 | $sql = 'SELECT al.location_id, a.ad_id, a.ad_code, a.ad_centering 82 | FROM ' . $this->ad_locations_table . ' al 83 | LEFT JOIN ' . $this->ads_table . ' a 84 | ON (al.ad_id = a.ad_id) 85 | WHERE a.ad_enabled = 1 86 | AND (a.ad_start_date = 0 87 | OR a.ad_start_date < ' . time() . ') 88 | AND (a.ad_end_date = 0 89 | OR a.ad_end_date > ' . time() . ") 90 | $sql_where_views 91 | $sql_where_clicks 92 | $sql_where_non_content 93 | $sql_where_user_groups 94 | AND " . $this->db->sql_in_set('al.location_id', $ad_locations) . ' 95 | ORDER BY al.location_id, (' . $this->sql_random() . ' * a.ad_priority) DESC'; 96 | $result = $this->db->sql_query($sql); 97 | $data = $this->db->sql_fetchrowset($result); 98 | $this->db->sql_freeresult($result); 99 | 100 | if (empty($data)) 101 | { 102 | return []; 103 | } 104 | 105 | $current_location_id = ''; 106 | $data = array_filter($data, function ($row) use (&$current_location_id) { 107 | $return = $current_location_id !== $row['location_id']; 108 | $current_location_id = $row['location_id']; 109 | return $return; 110 | }); 111 | 112 | return $data; 113 | } 114 | 115 | /** 116 | * Get all advertisements. 117 | * 118 | * @return array List of all ads 119 | */ 120 | public function get_all_ads() 121 | { 122 | $sql = 'SELECT ad_id, ad_priority, ad_name, ad_enabled, ad_start_date, ad_end_date, ad_views, ad_clicks, ad_views_limit, ad_clicks_limit 123 | FROM ' . $this->ads_table; 124 | $result = $this->db->sql_query($sql); 125 | $data = $this->db->sql_fetchrowset($result); 126 | $this->db->sql_freeresult($result); 127 | 128 | return $data; 129 | } 130 | 131 | /** 132 | * Get all owner's ads 133 | * 134 | * @param int $user_id Ad owner 135 | * @return array List of owner's ads 136 | */ 137 | public function get_ads_by_owner($user_id) 138 | { 139 | $sql = 'SELECT ad_id, ad_name, ad_enabled, ad_start_date, ad_end_date, ad_views, ad_views_limit, ad_clicks, ad_clicks_limit 140 | FROM ' . $this->ads_table . ' 141 | WHERE ad_owner = ' . (int) $user_id; 142 | $result = $this->db->sql_query($sql); 143 | $data = $this->db->sql_fetchrowset($result); 144 | $this->db->sql_freeresult($result); 145 | 146 | return $data; 147 | } 148 | 149 | /** 150 | * Increment views for specified ads 151 | * 152 | * Note, that views are incremented only by one even when 153 | * an ad is displayed multiple times on the same page. 154 | * 155 | * @param array $ad_ids IDs of ads to increment views 156 | * @return void 157 | */ 158 | public function increment_ads_views($ad_ids) 159 | { 160 | if (!empty($ad_ids)) 161 | { 162 | $sql = 'UPDATE ' . $this->ads_table . ' 163 | SET ad_views = ad_views + 1 164 | WHERE ' . $this->db->sql_in_set('ad_id', $ad_ids); 165 | $this->db->sql_query($sql); 166 | } 167 | } 168 | 169 | /** 170 | * Increment clicks for specified ad 171 | * 172 | * @param int $ad_id ID of an ad to increment clicks 173 | * @return void 174 | */ 175 | public function increment_ad_clicks($ad_id) 176 | { 177 | $sql = 'UPDATE ' . $this->ads_table . ' 178 | SET ad_clicks = ad_clicks + 1 179 | WHERE ad_id = ' . (int) $ad_id; 180 | $this->db->sql_query($sql); 181 | } 182 | 183 | /** 184 | * Insert new advertisement to the database 185 | * 186 | * @param array $data New ad data 187 | * @return int New advertisement ID 188 | */ 189 | public function insert_ad($data) 190 | { 191 | // extract ad groups here because it gets filtered in intersect_ad_data() 192 | $ad_groups = $data['ad_groups']; 193 | $data = $this->intersect_ad_data($data); 194 | 195 | // add a row to ads table 196 | $sql = 'INSERT INTO ' . $this->ads_table . ' ' . $this->db->sql_build_array('INSERT', $data); 197 | $this->db->sql_query($sql); 198 | $ad_id = (int) $this->db->sql_nextid(); 199 | 200 | $this->insert_ad_group_data($ad_id, $ad_groups); 201 | 202 | return $ad_id; 203 | } 204 | 205 | /** 206 | * Update advertisement 207 | * 208 | * @param int $ad_id Advertisement ID 209 | * @param array $data List of data to update in the database 210 | * @return int Number of affected rows. Can be used to determine if any ad has been updated. 211 | */ 212 | public function update_ad($ad_id, $data) 213 | { 214 | // extract ad groups here because it gets filtered in intersect_ad_data() 215 | $ad_groups = $data['ad_groups'] ?? []; 216 | $data = $this->intersect_ad_data($data); 217 | 218 | $sql = 'UPDATE ' . $this->ads_table . ' 219 | SET ' . $this->db->sql_build_array('UPDATE', $data) . ' 220 | WHERE ad_id = ' . (int) $ad_id; 221 | $this->db->sql_query($sql); 222 | $result = $this->db->sql_affectedrows(); 223 | 224 | $this->remove_ad_group_data($ad_id); 225 | $this->insert_ad_group_data($ad_id, $ad_groups); 226 | 227 | return $result; 228 | } 229 | 230 | /** 231 | * Delete advertisement 232 | * 233 | * @param int $ad_id Advertisement ID 234 | * @return int Number of affected rows. Can be used to determine if any ad has been deleted. 235 | */ 236 | public function delete_ad($ad_id) 237 | { 238 | $sql = 'DELETE FROM ' . $this->ads_table . ' 239 | WHERE ad_id = ' . (int) $ad_id; 240 | $this->db->sql_query($sql); 241 | 242 | return $this->db->sql_affectedrows(); 243 | } 244 | 245 | /** 246 | * Remove ad owner 247 | * 248 | * @param array $user_ids User IDs 249 | * @return void 250 | */ 251 | public function remove_ad_owner(array $user_ids) 252 | { 253 | if (empty($user_ids)) 254 | { 255 | return; 256 | } 257 | 258 | $sql = 'UPDATE ' . $this->ads_table . ' 259 | SET ad_owner = 0 260 | WHERE ' . $this->db->sql_in_set('ad_owner', $user_ids); 261 | $this->db->sql_query($sql); 262 | } 263 | 264 | /** 265 | * Get all locations for specified advertisement 266 | * 267 | * @param int $ad_id Advertisement ID 268 | * @return array List of template locations for specified ad 269 | */ 270 | public function get_ad_locations($ad_id) 271 | { 272 | $ad_locations = []; 273 | 274 | $sql = 'SELECT location_id 275 | FROM ' . $this->ad_locations_table . ' 276 | WHERE ad_id = ' . (int) $ad_id; 277 | $result = $this->db->sql_query($sql); 278 | while ($row = $this->db->sql_fetchrow($result)) 279 | { 280 | $ad_locations[] = $row['location_id']; 281 | } 282 | $this->db->sql_freeresult($result); 283 | 284 | return $ad_locations; 285 | } 286 | 287 | /** 288 | * Insert advertisement locations 289 | * 290 | * @param int $ad_id Advertisement ID 291 | * @param array $ad_locations List of template locations for this ad 292 | * @return void 293 | */ 294 | public function insert_ad_locations($ad_id, $ad_locations) 295 | { 296 | $sql_ary = []; 297 | foreach ($ad_locations as $ad_location) 298 | { 299 | $sql_ary[] = [ 300 | 'ad_id' => $ad_id, 301 | 'location_id' => $ad_location, 302 | ]; 303 | } 304 | $this->db->sql_multi_insert($this->ad_locations_table, $sql_ary); 305 | } 306 | 307 | /** 308 | * Delete advertisement locations 309 | * 310 | * @param int $ad_id Advertisement ID 311 | * @return void 312 | */ 313 | public function delete_ad_locations($ad_id) 314 | { 315 | $sql = 'DELETE FROM ' . $this->ad_locations_table . ' 316 | WHERE ad_id = ' . (int) $ad_id; 317 | $this->db->sql_query($sql); 318 | } 319 | 320 | /** 321 | * Load memberships of the user 322 | * 323 | * @param int $user_id User ID to load memberships 324 | * @return array List of group IDs user is member of 325 | */ 326 | public function load_memberships($user_id) 327 | { 328 | $memberships = []; 329 | $sql = 'SELECT group_id 330 | FROM ' . USER_GROUP_TABLE . ' 331 | WHERE user_id = ' . (int) $user_id . ' 332 | AND user_pending = 0'; 333 | $result = $this->db->sql_query($sql, 3600); 334 | while ($row = $this->db->sql_fetchrow($result)) 335 | { 336 | $memberships[] = $row['group_id']; 337 | } 338 | $this->db->sql_freeresult($result); 339 | return $memberships; 340 | } 341 | 342 | /** 343 | * Load all board groups 344 | * 345 | * @param int $ad_id Advertisement ID 346 | * @return array List of groups 347 | */ 348 | public function load_groups($ad_id) 349 | { 350 | $sql = 'SELECT g.group_id, g.group_name, ( 351 | SELECT COUNT(ad_id) 352 | FROM ' . $this->ad_group_table . ' ag 353 | WHERE ag.ad_id = ' . (int) $ad_id . ' 354 | AND ag.group_id = g.group_id 355 | ) as group_selected 356 | FROM ' . GROUPS_TABLE . " g 357 | WHERE g.group_name <> 'BOTS' 358 | ORDER BY g.group_name ASC"; 359 | $result = $this->db->sql_query($sql); 360 | $groups = $this->db->sql_fetchrowset($result); 361 | $this->db->sql_freeresult($result); 362 | 363 | return $groups; 364 | } 365 | 366 | /** 367 | * Make sure only necessary data make their way to SQL query 368 | * 369 | * @param array $data List of data to query the database 370 | * @return array Cleaned data that contain only valid keys 371 | */ 372 | protected function intersect_ad_data($data) 373 | { 374 | return array_intersect_key($data, [ 375 | 'ad_name' => '', 376 | 'ad_note' => '', 377 | 'ad_code' => '', 378 | 'ad_enabled' => '', 379 | 'ad_start_date' => '', 380 | 'ad_end_date' => '', 381 | 'ad_priority' => '', 382 | 'ad_views_limit' => '', 383 | 'ad_clicks_limit' => '', 384 | 'ad_owner' => '', 385 | 'ad_content_only' => '', 386 | 'ad_centering' => '', 387 | ]); 388 | } 389 | 390 | /** 391 | * Get the random statement for this database layer 392 | * Random function should generate a float value between 0 and 1 393 | * 394 | * @return string Random statement for current database layer 395 | */ 396 | protected function sql_random() 397 | { 398 | switch ($this->db->get_sql_layer()) 399 | { 400 | case 'oracle': 401 | return 'DBMS_RANDOM.VALUE'; 402 | 403 | case 'postgres': 404 | return 'RANDOM()'; 405 | 406 | // https://stackoverflow.com/a/35369410/2908600 407 | case 'sqlite': 408 | case 'sqlite3': 409 | return '(0.5 - RANDOM() / CAST(-9223372036854775808 AS REAL) / 2)'; 410 | 411 | // https://improve.dk/weighted-random-selections-in-sql-server/ 412 | case 'mssql': 413 | case 'mssql_odbc': 414 | case 'mssqlnative': 415 | return 'RAND(CAST(NEWID() AS VARBINARY))'; 416 | 417 | default: 418 | return 'RAND()'; 419 | } 420 | } 421 | 422 | /** 423 | * Add rows to ad_group table. 424 | * 425 | * @param int $ad_id Advertisement ID 426 | * @param array $ad_groups List of groups that should not see this ad 427 | * @return void 428 | */ 429 | protected function insert_ad_group_data($ad_id, $ad_groups) 430 | { 431 | $sql_ary = []; 432 | foreach ($ad_groups as $group) 433 | { 434 | $sql_ary[] = [ 435 | 'ad_id' => $ad_id, 436 | 'group_id' => $group, 437 | ]; 438 | } 439 | $this->db->sql_multi_insert($this->ad_group_table, $sql_ary); 440 | } 441 | 442 | /** 443 | * Remove all rows of specified ad in ad_group table 444 | * 445 | * @param int $ad_id Advertisement ID 446 | * @return void 447 | */ 448 | protected function remove_ad_group_data($ad_id) 449 | { 450 | $sql = 'DELETE FROM ' . $this->ad_group_table . ' 451 | WHERE ad_id = ' . (int) $ad_id; 452 | $this->db->sql_query($sql); 453 | } 454 | } 455 | -------------------------------------------------------------------------------- /adm/style/datetimepicker/MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 http://xdsoft.net 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /adm/style/datetimepicker/jquery.datetimepicker.min.css: -------------------------------------------------------------------------------- 1 | .xdsoft_datetimepicker{box-shadow:0 5px 15px -5px rgba(0,0,0,0.506);background:#fff;border-bottom:1px solid #bbb;border-left:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;padding:8px;padding-left:0;padding-top:2px;position:absolute;z-index:9999;-moz-box-sizing:border-box;box-sizing:border-box;display:none}.xdsoft_datetimepicker.xdsoft_rtl{padding:8px 0 8px 8px}.xdsoft_datetimepicker iframe{position:absolute;left:0;top:0;width:75px;height:210px;background:transparent;border:0}.xdsoft_datetimepicker button{border:none !important}.xdsoft_noselect{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.xdsoft_noselect::selection{background:transparent}.xdsoft_noselect::-moz-selection{background:transparent}.xdsoft_datetimepicker.xdsoft_inline{display:inline-block;position:static;box-shadow:none}.xdsoft_datetimepicker *{-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin:0}.xdsoft_datetimepicker .xdsoft_datepicker,.xdsoft_datetimepicker .xdsoft_timepicker{display:none}.xdsoft_datetimepicker .xdsoft_datepicker.active,.xdsoft_datetimepicker .xdsoft_timepicker.active{display:block}.xdsoft_datetimepicker .xdsoft_datepicker{width:224px;float:left;margin-left:8px}.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_datepicker{float:right;margin-right:8px;margin-left:0}.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_datepicker{width:256px}.xdsoft_datetimepicker .xdsoft_timepicker{width:58px;float:left;text-align:center;margin-left:8px;margin-top:0}.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker{float:right;margin-right:8px;margin-left:0}.xdsoft_datetimepicker .xdsoft_datepicker.active+.xdsoft_timepicker{margin-top:8px;margin-bottom:3px}.xdsoft_datetimepicker .xdsoft_mounthpicker{position:relative;text-align:center}.xdsoft_datetimepicker .xdsoft_label i,.xdsoft_datetimepicker .xdsoft_prev,.xdsoft_datetimepicker .xdsoft_next,.xdsoft_datetimepicker .xdsoft_today_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Q0NBRjI1NjM0M0UwMTFFNDk4NkFGMzJFQkQzQjEwRUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6Q0NBRjI1NjQ0M0UwMTFFNDk4NkFGMzJFQkQzQjEwRUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDQ0FGMjU2MTQzRTAxMUU0OTg2QUYzMkVCRDNCMTBFQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDQ0FGMjU2MjQzRTAxMUU0OTg2QUYzMkVCRDNCMTBFQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoNEP54AAAIOSURBVHja7Jq9TsMwEMcxrZD4WpBYeKUCe+kTMCACHZh4BFfHO/AAIHZGFhYkBBsSEqxsLCAgXKhbXYOTxh9pfJVP+qutnZ5s/5Lz2Y5I03QhWji2GIcgAokWgfCxNvcOCCGKqiSqhUp0laHOne05vdEyGMfkdxJDVjgwDlEQgYQBgx+ULJaWSXXS6r/ER5FBVR8VfGftTKcITNs+a1XpcFoExREIDF14AVIFxgQUS+h520cdud6wNkC0UBw6BCO/HoCYwBhD8QCkQ/x1mwDyD4plh4D6DDV0TAGyo4HcawLIBBSLDkHeH0Mg2yVP3l4TQMZQDDsEOl/MgHQqhMNuE0D+oBh0CIr8MAKyazBH9WyBuKxDWgbXfjNf32TZ1KWm/Ap1oSk/R53UtQ5xTh3LUlMmT8gt6g51Q9p+SobxgJQ/qmsfZhWywGFSl0yBjCLJCMgXail3b7+rumdVJ2YRss4cN+r6qAHDkPWjPjdJCF4n9RmAD/V9A/Wp4NQassDjwlB6XBiCxcJQWmZZb8THFilfy/lfrTvLghq2TqTHrRMTKNJ0sIhdo15RT+RpyWwFdY96UZ/LdQKBGjcXpcc1AlSFEfLmouD+1knuxBDUVrvOBmoOC/rEcN7OQxKVeJTCiAdUzUJhA2Oez9QTkp72OTVcxDcXY8iKNkxGAJXmJCOQwOa6dhyXsOa6XwEGAKdeb5ET3rQdAAAAAElFTkSuQmCC)}.xdsoft_datetimepicker .xdsoft_label i{opacity:.5;background-position:-92px -19px;display:inline-block;width:9px;height:20px;vertical-align:middle}.xdsoft_datetimepicker .xdsoft_prev{float:left;background-position:-20px 0}.xdsoft_datetimepicker .xdsoft_today_button{float:left;background-position:-70px 0;margin-left:5px}.xdsoft_datetimepicker .xdsoft_next{float:right;background-position:0 0}.xdsoft_datetimepicker .xdsoft_next,.xdsoft_datetimepicker .xdsoft_prev,.xdsoft_datetimepicker .xdsoft_today_button{background-color:transparent;background-repeat:no-repeat;border:0 none;cursor:pointer;display:block;height:30px;opacity:.5;-ms-filter:"alpha(opacity=50)";outline:medium none;overflow:hidden;padding:0;position:relative;text-indent:100%;white-space:nowrap;width:20px;min-width:0}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_next{float:none;background-position:-40px -15px;height:15px;width:30px;display:block;margin-left:14px;margin-top:7px}.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker .xdsoft_prev,.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker .xdsoft_next{float:none;margin-left:0;margin-right:14px}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev{background-position:-40px 0;margin-bottom:7px;margin-top:0}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box{height:151px;overflow:hidden;border-bottom:1px solid #ddd}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div{background:#f5f5f5;border-top:1px solid #ddd;color:#666;font-size:12px;text-align:center;border-collapse:collapse;cursor:pointer;border-bottom-width:0;height:25px;line-height:25px}.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div:first-child{border-top-width:0}.xdsoft_datetimepicker .xdsoft_today_button:hover,.xdsoft_datetimepicker .xdsoft_next:hover,.xdsoft_datetimepicker .xdsoft_prev:hover{opacity:1;-ms-filter:"alpha(opacity=100)"}.xdsoft_datetimepicker .xdsoft_label{display:inline;position:relative;z-index:9999;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:bold;background-color:#fff;float:left;width:182px;text-align:center;cursor:pointer}.xdsoft_datetimepicker .xdsoft_label:hover>span{text-decoration:underline}.xdsoft_datetimepicker .xdsoft_label:hover i{opacity:1.0}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select{border:1px solid #ccc;position:absolute;right:0;top:30px;z-index:101;display:none;background:#fff;max-height:160px;overflow-y:hidden}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select.xdsoft_monthselect{right:-7px}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select.xdsoft_yearselect{right:2px}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select>div>.xdsoft_option:hover{color:#fff;background:#ff8000}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select>div>.xdsoft_option{padding:2px 10px 2px 5px;text-decoration:none !important}.xdsoft_datetimepicker .xdsoft_label>.xdsoft_select>div>.xdsoft_option.xdsoft_current{background:#3af;box-shadow:#178fe5 0 1px 3px 0 inset;color:#fff;font-weight:700}.xdsoft_datetimepicker .xdsoft_month{width:100px;text-align:right}.xdsoft_datetimepicker .xdsoft_calendar{clear:both}.xdsoft_datetimepicker .xdsoft_year{width:48px;margin-left:5px}.xdsoft_datetimepicker .xdsoft_calendar table{border-collapse:collapse;width:100%}.xdsoft_datetimepicker .xdsoft_calendar td>div{padding-right:5px}.xdsoft_datetimepicker .xdsoft_calendar th{height:25px}.xdsoft_datetimepicker .xdsoft_calendar td,.xdsoft_datetimepicker .xdsoft_calendar th{width:14.2857142%;background:#f5f5f5;border:1px solid #ddd;color:#666;font-size:12px;text-align:right;vertical-align:middle;padding:0;border-collapse:collapse;cursor:pointer;height:25px}.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar td,.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar th{width:12.5%}.xdsoft_datetimepicker .xdsoft_calendar th{background:#f1f1f1}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_today{color:#3af}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_default{background:#ffe9d2;box-shadow:#ffb871 0 1px 4px 0 inset;color:#000}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_mint{background:#c1ffc9;box-shadow:#00dd1c 0 1px 4px 0 inset;color:#000}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_default,.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current{background:#3af;box-shadow:#178fe5 0 1px 3px 0 inset;color:#fff;font-weight:700}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month,.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled,.xdsoft_datetimepicker .xdsoft_time_box>div>div.xdsoft_disabled{opacity:.5;-ms-filter:"alpha(opacity=50)";cursor:default}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month.xdsoft_disabled{opacity:.2;-ms-filter:"alpha(opacity=20)"}.xdsoft_datetimepicker .xdsoft_calendar td:hover,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div:hover{color:#fff !important;background:#ff8000 !important;box-shadow:none !important}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current.xdsoft_disabled:hover,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current.xdsoft_disabled:hover{background:#3af !important;box-shadow:#178fe5 0 1px 3px 0 inset !important;color:#fff !important}.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled:hover,.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_disabled:hover{color:inherit !important;background:inherit !important;box-shadow:inherit !important}.xdsoft_datetimepicker .xdsoft_calendar th{font-weight:700;text-align:center;color:#999;cursor:default}.xdsoft_datetimepicker .xdsoft_copyright{color:#ccc !important;font-size:10px;clear:both;float:none;margin-left:8px}.xdsoft_datetimepicker .xdsoft_copyright a{color:#eee !important}.xdsoft_datetimepicker .xdsoft_copyright a:hover{color:#aaa !important}.xdsoft_time_box{position:relative;border:1px solid #ccc}.xdsoft_scrollbar>.xdsoft_scroller{background:#ccc !important;height:20px;border-radius:3px}.xdsoft_scrollbar{position:absolute;width:7px;right:0;top:0;bottom:0;cursor:pointer}.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_scrollbar{left:0;right:auto}.xdsoft_scroller_box{position:relative}.xdsoft_datetimepicker.xdsoft_dark{box-shadow:0 5px 15px -5px rgba(255,255,255,0.506);background:#000;border-bottom:1px solid #444;border-left:1px solid #333;border-right:1px solid #333;border-top:1px solid #333;color:#ccc}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box{border-bottom:1px solid #222}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box>div>div{background:#0a0a0a;border-top:1px solid #222;color:#999}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label{background-color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label>.xdsoft_select{border:1px solid #333;background:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label>.xdsoft_select>div>.xdsoft_option:hover{color:#000;background:#007fff}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label>.xdsoft_select>div>.xdsoft_option.xdsoft_current{background:#c50;box-shadow:#b03e00 0 1px 3px 0 inset;color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label i,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_prev,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_next,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_today_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUExQUUzOTA0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUExQUUzOTE0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQTFBRTM4RTQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQTFBRTM4RjQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pp0VxGEAAAIASURBVHja7JrNSgMxEMebtgh+3MSLr1T1Xn2CHoSKB08+QmR8Bx9A8e7RixdB9CKCoNdexIugxFlJa7rNZneTbLIpM/CnNLsdMvNjM8l0mRCiQ9Ye61IKCAgZAUnH+mU3MMZaHYChBnJUDzWOFZdVfc5+ZFLbrWDeXPwbxIqrLLfaeS0hEBVGIRQCEiZoHQwtlGSByCCdYBl8g8egTTAWoKQMRBRBcZxYlhzhKegqMOageErsCHVkk3hXIFooDgHB1KkHIHVgzKB4ADJQ/A1jAFmAYhkQqA5TOBtocrKrgXwQA8gcFIuAIO8sQSA7hidvPwaQGZSaAYHOUWJABhWWw2EMIH9QagQERU4SArJXo0ZZL18uvaxejXt/Em8xjVBXmvFr1KVm/AJ10tRe2XnraNqaJvKE3KHuUbfK1E+VHB0q40/y3sdQSxY4FHWeKJCunP8UyDdqJZenT3ntVV5jIYCAh20vT7ioP8tpf6E2lfEMwERe+whV1MHjwZB7PBiCxcGQWwKZKD62lfGNnP/1poFAA60T7rF1UgcKd2id3KDeUS+oLWV8DfWAepOfq00CgQabi9zjcgJVYVD7PVzQUAUGAQkbNJTBICDhgwYTjDYD6XeW08ZKh+A4pYkzenOxXUbvZcWz7E8ykRMnIHGX1XPl+1m2vPYpL+2qdb8CDAARlKFEz/ZVkAAAAABJRU5ErkJggg==)}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th{background:#0a0a0a;border:1px solid #222;color:#999}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th{background:#0e0e0e}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_today{color:#c50}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_default{background:#ffe9d2;box-shadow:#ffb871 0 1px 4px 0 inset;color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_mint{background:#c1ffc9;box-shadow:#00dd1c 0 1px 4px 0 inset;color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_default,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_current,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current{background:#c50;box-shadow:#b03e00 0 1px 3px 0 inset;color:#000}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td:hover,.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box>div>div:hover{color:#000 !important;background:#007fff !important}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th{color:#666}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright{color:#333 !important}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a{color:#111 !important}.xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a:hover{color:#555 !important}.xdsoft_dark .xdsoft_time_box{border:1px solid #333}.xdsoft_dark .xdsoft_scrollbar>.xdsoft_scroller{background:#333 !important}.xdsoft_datetimepicker .xdsoft_save_selected{display:block;border:1px solid #ddd !important;margin-top:5px;width:100%;color:#454551;font-size:13px}.xdsoft_datetimepicker .blue-gradient-button{font-family:"museo-sans","Book Antiqua",sans-serif;font-size:12px;font-weight:300;color:#82878c;height:28px;position:relative;padding:4px 17px 4px 33px;border:1px solid #d7d8da;background:-moz-linear-gradient(top,#fff 0,#f4f8fa 73%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(73%,#f4f8fa));background:-webkit-linear-gradient(top,#fff 0,#f4f8fa 73%);background:-o-linear-gradient(top,#fff 0,#f4f8fa 73%);background:-ms-linear-gradient(top,#fff 0,#f4f8fa 73%);background:linear-gradient(to bottom,#fff 0,#f4f8fa 73%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff',endColorstr='#f4f8fa',GradientType=0)}.xdsoft_datetimepicker .blue-gradient-button:hover,.xdsoft_datetimepicker .blue-gradient-button:focus,.xdsoft_datetimepicker .blue-gradient-button:hover span,.xdsoft_datetimepicker .blue-gradient-button:focus span{color:#454551;background:-moz-linear-gradient(top,#f4f8fa 0,#FFF 73%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#f4f8fa),color-stop(73%,#FFF));background:-webkit-linear-gradient(top,#f4f8fa 0,#FFF 73%);background:-o-linear-gradient(top,#f4f8fa 0,#FFF 73%);background:-ms-linear-gradient(top,#f4f8fa 0,#FFF 73%);background:linear-gradient(to bottom,#f4f8fa 0,#FFF 73%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f8fa',endColorstr='#FFF',GradientType=0)} 2 | -------------------------------------------------------------------------------- /adm/style/event/acp_overall_footer_after.html: -------------------------------------------------------------------------------- 1 | {% if S_PHPBB_ADS %} 2 | {% if not definition.INCLUDED_DATETIMEPICKERJS %} 3 | {% INCLUDECSS '@phpbb_ads/datetimepicker/jquery.datetimepicker.min.css' %} 4 | {% INCLUDEJS '@phpbb_ads/datetimepicker/jquery.datetimepicker.full.min.js' %} 5 | {% DEFINE INCLUDED_DATETIMEPICKERJS = true %} 6 | {% endif %} 7 | 8 | 78 | {% endif %} 79 | -------------------------------------------------------------------------------- /adm/style/manage_ads.html: -------------------------------------------------------------------------------- 1 | {% include 'overall_header.html' %} 2 | 3 | 4 | 5 | {% if S_ADD_AD or S_EDIT_AD %} 6 | {% INCLUDECSS '@phpbb_ads/phpbbads.css' %} 7 | 8 | « {{ lang('BACK') }} 9 | 10 |

{% if S_ADD_AD %}{{ lang('ACP_ADS_ADD') }}{% else %}{{ lang('ACP_ADS_EDIT') }}{% endif %}

11 | 12 | {% if PREVIEW %} 13 |
14 | {{ lang('PREVIEW') }} 15 | {% import '@phpbb_ads/phpbb_ads_macro.html' as preview %} 16 | {{ preview.renderAds(PREVIEW, 0, AD_CENTERING) }} 17 |
18 | {% endif %} 19 | 20 | {% if S_ERROR %} 21 |
22 |

{{ lang('WARNING') }}

23 |

{{ ERROR_MSG }}

24 |
25 | {% endif %} 26 | 27 |
28 |
29 | {{ lang('AD_SETTINGS') }} 30 |
31 |

{{ lang('AD_NAME_EXPLAIN') }}
32 |
33 |
34 |
35 |

{{ lang('AD_ENABLED_EXPLAIN') }}
36 |
37 |
38 |
39 |
40 |

{{ lang('AD_NOTE_EXPLAIN') }}
41 |
42 |
43 |
44 |

{{ lang('AD_CODE_EXPLAIN') }}
45 |
46 | 47 | 48 |
49 | {% if loops.analyser_results_notice or loops.analyser_results_warning %} 50 | {% if loops.analyser_results_notice %} 51 | {% for notice in loops.analyser_results_notice %} 52 |

{{ notice.MESSAGE }}

53 | {% endfor %} 54 | {% endif %} 55 | 56 | {% if loops.analyser_results_warning %} 57 | {% for warning in loops.analyser_results_warning %} 58 |

{{ warning.MESSAGE }}

59 | {% endfor %} 60 | {% endif %} 61 | {% elseif CODE_ANALYSED %} 62 |

{{ lang('EVERYTHING_OK') }}

63 | {% endif %} 64 |
65 |
66 |
67 |
68 |
69 | {{ lang('AD_BANNER') }} 70 |
71 |

{{ lang('BANNER_EXPLAIN') }}
72 |
73 | 74 | 75 |
76 |
77 |
78 |
79 | {{ lang('AD_PLACEMENT') }} 80 |
81 |

82 | {{ lang('AD_LOCATIONS_EXPLAIN') }}

83 | 84 | {{ lang('AD_LOCATIONS_VISUAL_DEMO') }} 85 |

{{ lang('VISUAL_DEMO_EXPLAIN') }} 86 |
87 |
88 |
99 |
100 |
101 |
102 |

{{ lang('AD_PRIORITY_EXPLAIN') }}
103 |
104 |
105 |
106 |

{{ lang('AD_CONTENT_ONLY_EXPLAIN') }}
107 |
108 |
109 |
110 |
111 |

{{ lang('AD_CENTERING_EXPLAIN') }}
112 |
113 |
114 |
115 |
116 |
117 | {{ lang('AD_OPTIONS') }} 118 |
119 |

{{ lang('AD_OWNER_EXPLAIN') }}
120 |
121 |
[ {{ lang('FIND_USERNAME') }} ]
122 |
123 |
124 |

{{ lang('AD_VIEWS_LIMIT_EXPLAIN') }}
125 |
126 |
127 |
128 |

{{ lang('AD_CLICKS_LIMIT_EXPLAIN') }}
129 |
130 |
131 |
132 |

{{ lang('AD_START_DATE_EXPLAIN') }}
133 |
134 |
135 |
136 |

{{ lang('AD_END_DATE_EXPLAIN') }}
137 |
138 |
139 |
140 |

{{ lang('HIDE_GROUPS_EXPLAIN') }}
141 |
146 |
147 |
148 |
149 |
150 |   151 |   152 | 153 | {% if S_EDIT_AD %} 154 | 155 | 156 | {% else %} 157 | 158 | {% endif %} 159 | {{ S_FORM_TOKEN }} 160 |
161 |
162 | 168 | 169 | {% else %} 170 | 171 |

{{ lang('ACP_MANAGE_ADS_TITLE') }}

172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | {% if S_VIEWS_ENABLED %}{% endif %} 181 | {% if S_CLICKS_ENABLED %}{% endif %} 182 | 183 | 184 | 185 | 186 | 187 | {% set NOW = "now"|date("U") %} 188 | {% for list in [ 189 | { 190 | 'heading': lang('ACTIVE_ADS'), 191 | 'loop': loops.ads, 192 | 'allow_enable': true 193 | }, 194 | { 195 | 'heading': lang('EXPIRED_ADS'), 196 | 'loop': loops.expired, 197 | 'allow_enable': false 198 | } 199 | ] %} 200 | {% if list.loop %} 201 | 202 | {% for ad in list.loop %} 203 | 204 | 205 | 206 | 207 | 212 | {% if S_VIEWS_ENABLED %} 213 | 218 | {% endif %} 219 | {% if S_CLICKS_ENABLED %} 220 | 225 | {% endif %} 226 | 235 | 236 | 237 | {% endfor %} 238 | {% elseif not loops.ads and not loops.expired and loop.last %} 239 | 240 | 241 | 242 | {% endif %} 243 | {% endfor %} 244 | 245 |
{{ lang('AD_NAME') }}{{ lang('AD_PRIORITY') }}{{ lang('AD_START_DATE') }}{{ lang('AD_END_DATE') }}{{ lang('AD_VIEWS') }}{{ lang('AD_CLICKS') }}{{ lang('STATUS') }}{{ lang('ACTION') }}
{{ list.heading }}{{ ad.NAME }}{{ ad.PRIORITY }}{{ ad.START_DATE ? ad.START_DATE|date(constant('\\phpbb\\ads\\ext::DATE_FORMAT')) }} 208 | {% if ad.END_DATE < NOW %}{% endif %} 209 | {{ ad.END_DATE ? ad.END_DATE|date(constant('\\phpbb\\ads\\ext::DATE_FORMAT')) }} 210 | {% if ad.END_DATE < NOW %}{% endif %} 211 | 214 | {% if ad.VIEWS_LIMIT and ad.VIEWS >= ad.VIEWS_LIMIT %}{% endif %} 215 | {{ ad.VIEWS }}{% if ad.VIEWS_LIMIT %} / {{ ad.VIEWS_LIMIT }}{% endif %} 216 | {% if ad.VIEWS_LIMIT and ad.VIEWS >= ad.VIEWS_LIMIT %}{% endif %} 217 | 221 | {% if ad.CLICKS_LIMIT and ad.CLICKS >= ad.CLICKS_LIMIT %}{% endif %} 222 | {{ ad.CLICKS }}{% if ad.CLICKS_LIMIT %} / {{ ad.CLICKS_LIMIT }}{% endif %} 223 | {% if ad.CLICKS_LIMIT and ad.CLICKS >= ad.CLICKS_LIMIT %}{% endif %} 224 | 227 | {% if list.allow_enable %} 228 | 229 | {% if ad.S_ENABLED %}{{ lang('ENABLED') }}{% else %}{{ lang('DISABLED') }}{% endif %} 230 | 231 | {% else %} 232 | {{ lang('DISABLED') }} 233 | {% endif %} 234 | {{ ICON_EDIT }} {{ ICON_DELETE }}
{{ lang('ACP_ADS_EMPTY') }}
246 | 247 |
248 |
249 | 250 | {{ S_FORM_TOKEN }} 251 |
252 |
253 | 254 | {% endif %} 255 | 256 | {% include 'overall_footer.html' %} 257 | -------------------------------------------------------------------------------- /adm/style/settings_ads.html: -------------------------------------------------------------------------------- 1 | {% include 'overall_header.html' %} 2 | 3 | 4 | 5 |

{{ lang('SETTINGS') }}

6 | 7 | {% if S_ERROR %} 8 |
9 |

{{ lang('WARNING') }}

10 |

{{ ERROR_MSG }}

11 |
12 | {% endif %} 13 | 14 |
15 |
16 | {{ lang('ADBLOCKER_LEGEND') }} 17 |
18 |

{{ lang('ADBLOCKER_MESSAGE_EXPLAIN') }}
19 |
20 | 25 |
26 |
27 |
28 |
29 | {{ lang('CLICKS_VIEWS_LEGEND') }} 30 |
31 |

{{ lang('ENABLE_VIEWS_EXPLAIN') }}
32 |
33 |
34 |
35 |
36 |

{{ lang('ENABLE_CLICKS_EXPLAIN') }}
37 |
38 |
39 |
40 |
41 |
42 |   43 | 44 | {{ S_FORM_TOKEN }} 45 |
46 |
47 | 48 | {% include 'overall_footer.html' %} 49 | -------------------------------------------------------------------------------- /analyser/manager.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\analyser; 12 | 13 | class manager 14 | { 15 | /** @var array Ad code analysis tests */ 16 | protected $tests; 17 | 18 | /** @var \phpbb\template\template */ 19 | protected $template; 20 | 21 | /** @var \phpbb\language\language */ 22 | protected $lang; 23 | 24 | /** 25 | * Construct an ad code analysis manager object 26 | * 27 | * @param array $tests Ad code analysis tests passed via the service container 28 | * @param \phpbb\template\template $template Template object 29 | * @param \phpbb\language\language $lang Language object 30 | */ 31 | public function __construct($tests, \phpbb\template\template $template, \phpbb\language\language $lang) 32 | { 33 | $this->tests = $tests; 34 | $this->template = $template; 35 | $this->lang = $lang; 36 | } 37 | 38 | /** 39 | * Test the ad code for potential problems. 40 | * 41 | * @param string $ad_code Advertisement code 42 | */ 43 | public function run($ad_code) 44 | { 45 | $results = array(); 46 | foreach ($this->tests as $test) 47 | { 48 | $result = $test->run($ad_code); 49 | if ($result !== false) 50 | { 51 | $results[] = $result; 52 | } 53 | } 54 | 55 | $this->assign_template_vars($results); 56 | } 57 | 58 | /** 59 | * Assign analyser results to template variables. 60 | * 61 | * @param array $results Analyser results 62 | */ 63 | protected function assign_template_vars($results) 64 | { 65 | foreach ($results as $result) 66 | { 67 | $this->template->assign_block_vars('analyser_results_' . $result['severity'], array( 68 | 'MESSAGE' => $this->lang->lang($result['message']), 69 | )); 70 | } 71 | 72 | $this->template->assign_var('CODE_ANALYSED', true); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /analyser/test/alert.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\analyser\test; 12 | 13 | class alert implements test_interface 14 | { 15 | /** 16 | * {@inheritDoc} 17 | * 18 | * Javascript alert() test. 19 | * This test checks for the presence of alert() in an ad code. 20 | * There is no reason why ad would trigger alert, so it's 21 | * categorized as warning. 22 | */ 23 | public function run($ad_code) 24 | { 25 | if (preg_match('/alert\s*\(/U', $ad_code)) 26 | { 27 | return array( 28 | 'severity' => 'warning', 29 | 'message' => 'ALERT_USAGE', 30 | ); 31 | } 32 | 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /analyser/test/location_href.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\analyser\test; 12 | 13 | class location_href implements test_interface 14 | { 15 | /** 16 | * {@inheritDoc} 17 | * 18 | * Javascript redirect using window.location.href test. 19 | * This test checks for the presence of redirect in an ad code. 20 | * There is no reason why ad would redirect user to another page, 21 | * so it's categorized as warning. 22 | */ 23 | public function run($ad_code) 24 | { 25 | if (preg_match('/location\.href(\s)*=/U', $ad_code)) 26 | { 27 | return array( 28 | 'severity' => 'warning', 29 | 'message' => 'LOCATION_CHANGE', 30 | ); 31 | } 32 | 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /analyser/test/script_without_async.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\analyser\test; 12 | 13 | class script_without_async implements test_interface 14 | { 15 | /** 16 | * {@inheritDoc} 17 | * 18 | * Synchronously loaded scripts test. 19 | * This test looks for scripts that aren't using `async` attribute 20 | * to load itself asynchronously. Such scripts slow down page rendering 21 | * time and should be made asynchronous. 22 | */ 23 | public function run($ad_code) 24 | { 25 | if (preg_match_all('/<script(.*)src(.*)>/U', $ad_code, $matches)) 26 | { 27 | foreach ($matches[1] as $match) 28 | { 29 | if (!preg_match('/ async/', $match)) 30 | { 31 | return array( 32 | 'severity' => 'notice', 33 | 'message' => 'SCRIPT_WITHOUT_ASYNC', 34 | ); 35 | } 36 | } 37 | } 38 | 39 | return false; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /analyser/test/test_interface.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\analyser\test; 12 | 13 | /** 14 | * Interface for ad code analysis tests 15 | */ 16 | interface test_interface 17 | { 18 | /** 19 | * Test ad code for potential problems. 20 | * 21 | * @param string $ad_code Advertisement code 22 | * @return mixed List of notices and warnings or false when there are none. 23 | */ 24 | public function run($ad_code); 25 | } 26 | -------------------------------------------------------------------------------- /analyser/test/untrusted_connection.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\analyser\test; 12 | 13 | class untrusted_connection implements test_interface 14 | { 15 | /** @var \phpbb\request\request */ 16 | protected $request; 17 | 18 | /** 19 | * Construct an ad code analysis manager object 20 | * 21 | * @param \phpbb\request\request $request Request object 22 | */ 23 | public function __construct(\phpbb\request\request $request) 24 | { 25 | $this->request = $request; 26 | } 27 | 28 | /** 29 | * {@inheritDoc} 30 | * 31 | * Untrusted connection test. 32 | * When board runs on HTTPS and ad tries to load a file from 33 | * HTTP source, browser throws a warning. We should prevent that. 34 | */ 35 | public function run($ad_code) 36 | { 37 | $is_https = $this->request->server('HTTPS', false); 38 | if ($is_https && preg_match('/http[^s]/', $ad_code)) 39 | { 40 | return array( 41 | 'severity' => 'warning', 42 | 'message' => 'UNSECURE_CONNECTION', 43 | ); 44 | } 45 | 46 | return false; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /banner/banner.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\banner; 12 | 13 | class banner 14 | { 15 | /** @var \phpbb\files\upload */ 16 | protected $files_upload; 17 | 18 | /** @var \phpbb\filesystem\filesystem_interface */ 19 | protected $filesystem; 20 | 21 | /** @var string */ 22 | protected $root_path; 23 | 24 | /** @var \phpbb\files\filespec */ 25 | protected $file; 26 | 27 | /** 28 | * Constructor 29 | * 30 | * @param \phpbb\files\upload $files_upload Files upload object 31 | * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem object 32 | * @param string $root_path Root path 33 | */ 34 | public function __construct(\phpbb\files\upload $files_upload, \phpbb\filesystem\filesystem_interface $filesystem, $root_path) 35 | { 36 | $this->files_upload = $files_upload; 37 | $this->filesystem = $filesystem; 38 | $this->root_path = $root_path; 39 | } 40 | 41 | public function set_file($file) 42 | { 43 | $this->file = $file; 44 | } 45 | 46 | /** 47 | * Create storage directory for banners uploaded by Ads Management 48 | * 49 | * @throws \phpbb\filesystem\exception\filesystem_exception 50 | */ 51 | public function create_storage_dir() 52 | { 53 | if (!$this->filesystem->exists($this->root_path . 'images/phpbb_ads')) 54 | { 55 | $this->filesystem->mkdir($this->root_path . 'images/phpbb_ads'); 56 | } 57 | } 58 | 59 | /** 60 | * Handle banner upload 61 | * 62 | * @throws \phpbb\exception\runtime_exception 63 | * @return string Filename 64 | */ 65 | public function upload() 66 | { 67 | // Set file restrictions 68 | $this->files_upload->reset_vars(); 69 | $this->files_upload->set_allowed_extensions(array('gif', 'jpg', 'jpeg', 'png')); 70 | 71 | // Upload file 72 | $this->set_file($this->files_upload->handle_upload('files.types.form', 'banner')); 73 | $this->file->clean_filename('unique_ext'); 74 | 75 | // Move file to proper location 76 | if (!$this->file->move_file('images/phpbb_ads')) 77 | { 78 | $this->file->set_error('FILE_MOVE_UNSUCCESSFUL'); 79 | } 80 | 81 | if (count($this->file->error)) 82 | { 83 | throw new \phpbb\exception\runtime_exception($this->file->error[0]); 84 | } 85 | 86 | return $this->file->get('realname'); 87 | } 88 | 89 | /** 90 | * Remove file from the filesystem 91 | */ 92 | public function remove() 93 | { 94 | $this->file->remove(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpbb/ads", 3 | "type": "phpbb-extension", 4 | "description": "An extension for phpBB that allows administrators to manage and display advertisements on their forums.", 5 | "homepage": "https://www.phpbb.com/customise/db/extension/ads/", 6 | "version": "3.0.0", 7 | "keywords": ["phpbb", "extension", "advertisement"], 8 | "license": "GPL-2.0-only", 9 | "authors": [ 10 | { 11 | "name": "Jakub Senko", 12 | "email": "jakubsenko@gmail.com", 13 | "role": "Extension Developer" 14 | }, 15 | { 16 | "name": "Matt Friedman", 17 | "homepage": "https://imattpro.github.io", 18 | "role": "Extensions Development Team Lead" 19 | }, 20 | { 21 | "name": "Derky", 22 | "homepage": "http://www.derky.nl", 23 | "role": "Extensions Team" 24 | } 25 | ], 26 | "require": { 27 | "php": ">=7.1.3", 28 | "composer/installers": "~1.0" 29 | }, 30 | "require-dev": { 31 | "phing/phing": "~2.4" 32 | }, 33 | "extra": { 34 | "display-name": "Advertisement Management", 35 | "soft-require": { 36 | "phpbb/phpbb": ">=3.3.2,<4.0.0@dev" 37 | }, 38 | "version-check": { 39 | "host": "www.phpbb.com", 40 | "directory": "/customise/db/extension/ads", 41 | "filename": "version_check", 42 | "ssl": true 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /config/analyser.yml: -------------------------------------------------------------------------------- 1 | services: 2 | phpbb.ads.analyser.manager: 3 | class: phpbb\ads\analyser\manager 4 | arguments: 5 | - '@phpbb.ads.analyser.test_collection' 6 | - '@template' 7 | - '@language' 8 | 9 | # ----- Analyser tests ----- 10 | phpbb.ads.analyser.test_collection: 11 | class: phpbb\di\service_collection 12 | arguments: 13 | - '@service_container' 14 | tags: 15 | - { name: service_collection, tag: phpbb.ads.analyser.test } 16 | 17 | phpbb.ads.analyser.test.alert: 18 | class: phpbb\ads\analyser\test\alert 19 | tags: 20 | - { name: phpbb.ads.analyser.test } 21 | 22 | phpbb.ads.analyser.test.location_href: 23 | class: phpbb\ads\analyser\test\location_href 24 | tags: 25 | - { name: phpbb.ads.analyser.test } 26 | 27 | phpbb.ads.analyser.test.script_without_async: 28 | class: phpbb\ads\analyser\test\script_without_async 29 | tags: 30 | - { name: phpbb.ads.analyser.test } 31 | 32 | phpbb.ads.analyser.test.untrusted_connection: 33 | class: phpbb\ads\analyser\test\untrusted_connection 34 | arguments: 35 | - '@request' 36 | tags: 37 | - { name: phpbb.ads.analyser.test } 38 | -------------------------------------------------------------------------------- /config/location.yml: -------------------------------------------------------------------------------- 1 | services: 2 | phpbb.ads.location.manager: 3 | class: phpbb\ads\location\manager 4 | arguments: 5 | - '@phpbb.ads.location.type_collection' 6 | 7 | phpbb.ads.location.type.base: 8 | class: phpbb\ads\location\type\base 9 | abstract: true 10 | arguments: 11 | - '@user' 12 | - '@language' 13 | 14 | # ----- Template locations ----- 15 | phpbb.ads.location.type_collection: 16 | class: phpbb\di\service_collection 17 | arguments: 18 | - '@service_container' 19 | tags: 20 | - { name: service_collection, tag: phpbb.ads.location.type } 21 | 22 | phpbb.ads.location.type.above_footer: 23 | class: phpbb\ads\location\type\above_footer 24 | parent: phpbb.ads.location.type.base 25 | tags: 26 | - { name: phpbb.ads.location.type } 27 | 28 | phpbb.ads.location.type.above_header: 29 | class: phpbb\ads\location\type\above_header 30 | parent: phpbb.ads.location.type.base 31 | tags: 32 | - { name: phpbb.ads.location.type } 33 | 34 | phpbb.ads.location.type.after_first_post: 35 | class: phpbb\ads\location\type\after_first_post 36 | parent: phpbb.ads.location.type.base 37 | tags: 38 | - { name: phpbb.ads.location.type } 39 | 40 | phpbb.ads.location.type.after_footer_navbar: 41 | class: phpbb\ads\location\type\after_footer_navbar 42 | parent: phpbb.ads.location.type.base 43 | tags: 44 | - { name: phpbb.ads.location.type } 45 | 46 | phpbb.ads.location.type.after_header_navbar: 47 | class: phpbb\ads\location\type\after_header_navbar 48 | parent: phpbb.ads.location.type.base 49 | tags: 50 | - { name: phpbb.ads.location.type } 51 | 52 | phpbb.ads.location.type.after_not_first_post: 53 | class: phpbb\ads\location\type\after_not_first_post 54 | parent: phpbb.ads.location.type.base 55 | tags: 56 | - { name: phpbb.ads.location.type } 57 | 58 | phpbb.ads.location.type.after_posts: 59 | class: phpbb\ads\location\type\after_posts 60 | parent: phpbb.ads.location.type.base 61 | tags: 62 | - { name: phpbb.ads.location.type } 63 | 64 | phpbb.ads.location.type.after_profile: 65 | class: phpbb\ads\location\type\after_profile 66 | parent: phpbb.ads.location.type.base 67 | tags: 68 | - { name: phpbb.ads.location.type } 69 | 70 | phpbb.ads.location.type.after_quickreply: 71 | class: phpbb\ads\location\type\after_quickreply 72 | parent: phpbb.ads.location.type.base 73 | tags: 74 | - { name: phpbb.ads.location.type } 75 | 76 | phpbb.ads.location.type.before_posts: 77 | class: phpbb\ads\location\type\before_posts 78 | parent: phpbb.ads.location.type.base 79 | tags: 80 | - { name: phpbb.ads.location.type } 81 | 82 | phpbb.ads.location.type.before_profile: 83 | class: phpbb\ads\location\type\before_profile 84 | parent: phpbb.ads.location.type.base 85 | tags: 86 | - { name: phpbb.ads.location.type } 87 | 88 | phpbb.ads.location.type.before_quickreply: 89 | class: phpbb\ads\location\type\before_quickreply 90 | parent: phpbb.ads.location.type.base 91 | tags: 92 | - { name: phpbb.ads.location.type } 93 | 94 | phpbb.ads.location.type.below_footer: 95 | class: phpbb\ads\location\type\below_footer 96 | parent: phpbb.ads.location.type.base 97 | tags: 98 | - { name: phpbb.ads.location.type } 99 | 100 | phpbb.ads.location.type.below_header: 101 | class: phpbb\ads\location\type\below_header 102 | parent: phpbb.ads.location.type.base 103 | tags: 104 | - { name: phpbb.ads.location.type } 105 | 106 | phpbb.ads.location.type.pop_up: 107 | class: phpbb\ads\location\type\pop_up 108 | parent: phpbb.ads.location.type.base 109 | arguments: 110 | - '@request' 111 | - '@config' 112 | - '@template' 113 | tags: 114 | - { name: phpbb.ads.location.type } 115 | 116 | phpbb.ads.location.type.scripts: 117 | class: phpbb\ads\location\type\scripts 118 | parent: phpbb.ads.location.type.base 119 | tags: 120 | - { name: phpbb.ads.location.type } 121 | 122 | phpbb.ads.location.type.slide_up: 123 | class: phpbb\ads\location\type\slide_up 124 | parent: phpbb.ads.location.type.base 125 | tags: 126 | - { name: phpbb.ads.location.type } 127 | -------------------------------------------------------------------------------- /config/routing.yml: -------------------------------------------------------------------------------- 1 | phpbb_ads_click: 2 | path: /adsclick/{data} 3 | defaults: { _controller: phpbb.ads.increment.controller:handle, mode: clicks } 4 | requirements: 5 | data: \d+ 6 | 7 | phpbb_ads_view: 8 | path: /adsview/{data} 9 | defaults: { _controller: phpbb.ads.increment.controller:handle, mode: views } 10 | requirements: 11 | data: (\d+-)*\d+ 12 | 13 | phpbb_ads_visual_demo: 14 | path: /phpbbads_visual_demo/{action} 15 | defaults: { _controller: phpbb.ads.visual_demo.controller:handle } 16 | requirements: 17 | action: enable|disable 18 | -------------------------------------------------------------------------------- /config/services.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: tables.yml } 3 | - { resource: analyser.yml } 4 | - { resource: location.yml } 5 | 6 | services: 7 | phpbb.ads.ad.manager: 8 | class: phpbb\ads\ad\manager 9 | arguments: 10 | - '@dbal.conn' 11 | - '@config' 12 | - '%phpbb.ads.tables.ads%' 13 | - '%phpbb.ads.tables.ad_locations%' 14 | - '%phpbb.ads.tables.ad_group%' 15 | 16 | phpbb.ads.banner.banner: 17 | class: phpbb\ads\banner\banner 18 | arguments: 19 | - '@files.upload' 20 | - '@filesystem' 21 | - '%core.root_path%' 22 | - '%phpbb.ads.tables.ad_locations%' 23 | 24 | phpbb.ads.helper: 25 | class: phpbb\ads\controller\helper 26 | arguments: 27 | - '@user' 28 | - '@user_loader' 29 | - '@language' 30 | - '@template' 31 | - '@log' 32 | - '@phpbb.ads.ad.manager' 33 | - '@phpbb.ads.location.manager' 34 | - '@group_helper' 35 | - '%core.root_path%' 36 | - '%core.php_ext%' 37 | 38 | phpbb.ads.admin.input: 39 | class: phpbb\ads\controller\admin_input 40 | arguments: 41 | - '@user' 42 | - '@user_loader' 43 | - '@language' 44 | - '@request' 45 | - '@phpbb.ads.banner.banner' 46 | 47 | phpbb.ads.listener: 48 | class: phpbb\ads\event\main_listener 49 | arguments: 50 | - '@template' 51 | - '@template_context' 52 | - '@user' 53 | - '@config' 54 | - '@phpbb.ads.ad.manager' 55 | - '@phpbb.ads.location.manager' 56 | - '@controller.helper' 57 | - '@request' 58 | - '@cache.driver' 59 | - '%core.php_ext%' 60 | tags: 61 | - { name: event.listener } 62 | 63 | # -------- Controllers -------- # 64 | phpbb.ads.admin.controller: 65 | class: phpbb\ads\controller\admin_controller 66 | arguments: 67 | - '@template' 68 | - '@language' 69 | - '@request' 70 | - '@phpbb.ads.ad.manager' 71 | - '@config_text' 72 | - '@config' 73 | - '@phpbb.ads.admin.input' 74 | - '@phpbb.ads.helper' 75 | - '@phpbb.ads.analyser.manager' 76 | - '@controller.helper' 77 | - '%core.root_path%' 78 | - '%core.php_ext%' 79 | 80 | phpbb.ads.increment.controller: 81 | class: phpbb\ads\controller\increment_controller 82 | arguments: 83 | - '@phpbb.ads.ad.manager' 84 | - '@request' 85 | 86 | phpbb.ads.ucp.controller: 87 | class: phpbb\ads\controller\ucp_controller 88 | arguments: 89 | - '@phpbb.ads.ad.manager' 90 | - '@phpbb.ads.helper' 91 | - '@user' 92 | - '@language' 93 | - '@template' 94 | - '@config' 95 | 96 | phpbb.ads.visual_demo.controller: 97 | class: phpbb\ads\controller\visual_demo_controller 98 | arguments: 99 | - '@auth' 100 | - '@config' 101 | - '@request' 102 | - '@user' 103 | - '%core.root_path%' 104 | - '%core.php_ext%' 105 | -------------------------------------------------------------------------------- /config/tables.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | phpbb.ads.tables.ads: '%core.table_prefix%ads' 3 | phpbb.ads.tables.ad_group: '%core.table_prefix%ad_group' 4 | phpbb.ads.tables.ad_locations: '%core.table_prefix%ad_locations' 5 | -------------------------------------------------------------------------------- /controller/admin_input.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\controller; 12 | 13 | use phpbb\ads\ext; 14 | 15 | /** 16 | * Admin input 17 | */ 18 | class admin_input 19 | { 20 | /** @var \phpbb\user */ 21 | protected $user; 22 | 23 | /** @var \phpbb\user_loader */ 24 | protected $user_loader; 25 | 26 | /** @var \phpbb\language\language */ 27 | protected $language; 28 | 29 | /** @var \phpbb\request\request */ 30 | protected $request; 31 | 32 | /** @var \phpbb\ads\banner\banner */ 33 | protected $banner; 34 | 35 | /** @var array Form validation errors */ 36 | protected $errors = array(); 37 | 38 | /** 39 | * Constructor 40 | * 41 | * @param \phpbb\user $user User object 42 | * @param \phpbb\user_loader $user_loader User loader object 43 | * @param \phpbb\language\language $language Language object 44 | * @param \phpbb\request\request $request Request object 45 | * @param \phpbb\ads\banner\banner $banner Banner upload object 46 | */ 47 | public function __construct(\phpbb\user $user, \phpbb\user_loader $user_loader, \phpbb\language\language $language, \phpbb\request\request $request, \phpbb\ads\banner\banner $banner) 48 | { 49 | $this->user = $user; 50 | $this->user_loader = $user_loader; 51 | $this->language = $language; 52 | $this->request = $request; 53 | $this->banner = $banner; 54 | 55 | add_form_key('phpbb_ads'); 56 | } 57 | 58 | /** 59 | * Gets all errors 60 | * 61 | * @return array Errors 62 | */ 63 | public function get_errors() 64 | { 65 | return $this->errors; 66 | } 67 | 68 | /** 69 | * Returns number of errors. 70 | * 71 | * @return int Number of errors 72 | */ 73 | public function has_errors() 74 | { 75 | return count($this->errors); 76 | } 77 | 78 | /** 79 | * Get admin form data. 80 | * 81 | * @return array Form data 82 | */ 83 | public function get_form_data() 84 | { 85 | $data = array( 86 | 'ad_name' => $this->request->variable('ad_name', '', true), 87 | 'ad_note' => $this->request->variable('ad_note', '', true), 88 | 'ad_code' => $this->request->variable('ad_code', '', true), 89 | 'ad_enabled' => $this->request->variable('ad_enabled', 0), 90 | 'ad_locations' => $this->request->variable('ad_locations', array('')), 91 | 'ad_start_date' => $this->request->variable('ad_start_date', ''), 92 | 'ad_end_date' => $this->request->variable('ad_end_date', ''), 93 | 'ad_priority' => $this->request->variable('ad_priority', ext::DEFAULT_PRIORITY), 94 | 'ad_content_only' => $this->request->variable('ad_content_only', 0), 95 | 'ad_views_limit' => $this->request->variable('ad_views_limit', 0), 96 | 'ad_clicks_limit' => $this->request->variable('ad_clicks_limit', 0), 97 | 'ad_owner' => $this->request->variable('ad_owner', '', true), 98 | 'ad_groups' => $this->request->variable('ad_groups', array(0)), 99 | 'ad_centering' => $this->request->variable('ad_centering', true), 100 | ); 101 | 102 | // Validate form key 103 | if (!check_form_key('phpbb_ads')) 104 | { 105 | $this->errors[] = 'FORM_INVALID'; 106 | } 107 | 108 | // Validate each property. Some validators update the property value. Errors are added to $this->errors. 109 | foreach ($data as $prop_name => $prop_val) 110 | { 111 | $method = 'validate_' . $prop_name; 112 | if (method_exists($this, $method)) 113 | { 114 | $data[$prop_name] = $this->{$method}($prop_val); 115 | } 116 | } 117 | 118 | // Make sure start date is sooner than end date 119 | if ($data['ad_start_date'] != 0 && $data['ad_end_date'] != 0 && $data['ad_start_date'] > $data['ad_end_date']) 120 | { 121 | $this->errors[] = $this->language->lang('END_DATE_TOO_SOON'); 122 | } 123 | 124 | return $data; 125 | } 126 | 127 | /** 128 | * Upload image and return updated ad code or of new banner when using ajax. 129 | * 130 | * @param string $ad_code Current ad code 131 | * @return string \phpbb\json_response when request is ajax or updated ad code otherwise. 132 | */ 133 | public function banner_upload($ad_code) 134 | { 135 | try 136 | { 137 | $this->banner->create_storage_dir(); 138 | $realname = $this->banner->upload(); 139 | 140 | $banner_html = ''; 141 | 142 | if ($this->request->is_ajax()) 143 | { 144 | $this->send_ajax_response(true, $banner_html); 145 | } 146 | 147 | $ad_code = ($ad_code ? $ad_code . "\n\n" : '') . $banner_html; 148 | } 149 | catch (\phpbb\exception\runtime_exception $e) 150 | { 151 | $this->banner->remove(); 152 | 153 | if ($this->request->is_ajax()) 154 | { 155 | $this->send_ajax_response(false, $this->language->lang($e->getMessage())); 156 | } 157 | 158 | $this->errors[] = $this->language->lang($e->getMessage()); 159 | } 160 | 161 | return $ad_code; 162 | } 163 | 164 | /** 165 | * Validate advertisement name 166 | * 167 | * Ad name is required and must not be empty. Ad name must 168 | * also be less than 255 characters. 169 | * 170 | * @param string $ad_name Advertisement name 171 | * @return string Advertisement name 172 | */ 173 | protected function validate_ad_name($ad_name) 174 | { 175 | if ($ad_name === '') 176 | { 177 | $this->errors[] = 'AD_NAME_REQUIRED'; 178 | } 179 | 180 | if (truncate_string($ad_name, ext::MAX_NAME_LENGTH) !== $ad_name) 181 | { 182 | $this->errors[] = $this->language->lang('AD_NAME_TOO_LONG', ext::MAX_NAME_LENGTH); 183 | } 184 | 185 | return $ad_name; 186 | } 187 | 188 | /** 189 | * Validate advertisement code 190 | * 191 | * Ad code should not contain 4-byte Emoji characters. 192 | * 193 | * @param string $ad_code Advertisement code 194 | * @return string Advertisement code 195 | */ 196 | protected function validate_ad_code($ad_code) 197 | { 198 | if (preg_match_all('/[\x{10000}-\x{10FFFF}]/u', $ad_code, $matches)) 199 | { 200 | $characters = implode(' ', $matches[0]); 201 | $this->errors[] = $this->language->lang('AD_CODE_ILLEGAL_CHARS', $characters); 202 | } 203 | 204 | return $ad_code; 205 | } 206 | 207 | /** 208 | * Validate advertisement start date 209 | * 210 | * @param string $start_date Advertisement start date 211 | * @return int The start date converted to timestamp if valid, otherwise 0. 212 | */ 213 | protected function validate_ad_start_date($start_date) 214 | { 215 | return $this->validate_date($start_date, 'START'); 216 | } 217 | 218 | /** 219 | * Validate advertisement end date. 220 | * 221 | * @param string $end_date Advertisement end date 222 | * @return int The end date converted to timestamp if valid, otherwise 0. 223 | */ 224 | protected function validate_ad_end_date($end_date) 225 | { 226 | return $this->validate_date($end_date, 'END'); 227 | } 228 | 229 | /** 230 | * Validate advertisement priority 231 | * 232 | * Ad priority must be an integer between 1 and 10. 233 | * 234 | * @param int $ad_priority Advertisement priority 235 | * @return int Advertisement priority 236 | */ 237 | protected function validate_ad_priority($ad_priority) 238 | { 239 | if ($ad_priority < 1 || $ad_priority > 10) 240 | { 241 | $this->errors[] = 'AD_PRIORITY_INVALID'; 242 | } 243 | 244 | return $ad_priority; 245 | } 246 | 247 | /** 248 | * Validate advertisement views limit 249 | * 250 | * Clicks must be a positive integer. 251 | * 252 | * @param int $ad_views_limit Advertisement views limit 253 | * @return int Advertisement views limit 254 | */ 255 | protected function validate_ad_views_limit($ad_views_limit) 256 | { 257 | if ($ad_views_limit < 0) 258 | { 259 | $this->errors[] = 'AD_VIEWS_LIMIT_INVALID'; 260 | } 261 | 262 | return $ad_views_limit; 263 | } 264 | 265 | /** 266 | * Validate advertisement clicks limit 267 | * 268 | * Clicks must be a positive integer. 269 | * 270 | * @param int $ad_clicks_limit Advertisement clicks limit 271 | * @return int Advertisement clicks limit 272 | */ 273 | protected function validate_ad_clicks_limit($ad_clicks_limit) 274 | { 275 | if ($ad_clicks_limit < 0) 276 | { 277 | $this->errors[] = 'AD_CLICKS_LIMIT_INVALID'; 278 | } 279 | 280 | return $ad_clicks_limit; 281 | } 282 | 283 | /** 284 | * Validate advertisement owner 285 | * 286 | * If ad owner name given, get their ID. If the ID returned is ANONYMOUS, 287 | * set an error because the user name given doesn't exist. 288 | * 289 | * @param string $ad_owner User name 290 | * @return int User id if user exists, otherwise 0. 291 | */ 292 | protected function validate_ad_owner($ad_owner) 293 | { 294 | $user_id = 0; 295 | if (!empty($ad_owner) && ANONYMOUS === ($user_id = (int) $this->user_loader->load_user_by_username($ad_owner))) 296 | { 297 | $this->errors[] = 'AD_OWNER_INVALID'; 298 | } 299 | 300 | return ANONYMOUS !== $user_id ? $user_id : 0; 301 | } 302 | 303 | /** 304 | * Send ajax response 305 | * 306 | * @param bool $success Is request successful? 307 | * @param string $text Text to return 308 | */ 309 | protected function send_ajax_response($success, $text) 310 | { 311 | $json_response = new \phpbb\json_response; 312 | $json_response->send(array( 313 | 'success' => $success, 314 | 'title' => $this->language->lang('INFORMATION'), 315 | 'text' => $text, 316 | )); 317 | } 318 | 319 | /** 320 | * Validate advertisement date 321 | * 322 | * The date must use the expected format of YYYY-MM-DD. 323 | * If the date is valid, convert it to a timestamp and then 324 | * make sure the timestamp is less than the current time. 325 | * 326 | * @param string $date Advertisement date 327 | * @return int The date converted to timestamp if valid, otherwise 0. 328 | */ 329 | protected function validate_date($date, $type) 330 | { 331 | $timestamp = 0; 332 | if (preg_match('#^\d{4}-\d{2}-\d{2}$#', $date)) 333 | { 334 | $timestamp = (int) $this->user->get_timestamp_from_format(ext::DATE_FORMAT, $date); 335 | 336 | if ($timestamp < time()) 337 | { 338 | $this->errors[] = 'AD_' . $type . '_DATE_INVALID'; 339 | } 340 | } 341 | else if ($date !== '') 342 | { 343 | $this->errors[] = 'AD_' . $type . '_DATE_INVALID'; 344 | } 345 | 346 | return $timestamp; 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /controller/helper.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\controller; 12 | 13 | /** 14 | * Helper 15 | */ 16 | class helper 17 | { 18 | /** @var \phpbb\user */ 19 | protected $user; 20 | 21 | /** @var \phpbb\user_loader */ 22 | protected $user_loader; 23 | 24 | /** @var \phpbb\language\language */ 25 | protected $language; 26 | 27 | /** @var \phpbb\template\template */ 28 | protected $template; 29 | 30 | /** @var \phpbb\log\log */ 31 | protected $log; 32 | 33 | /** @var \phpbb\ads\ad\manager */ 34 | protected $manager; 35 | 36 | /** @var \phpbb\ads\location\manager */ 37 | protected $location_manager; 38 | 39 | /** @var \phpbb\group\helper */ 40 | protected $group_helper; 41 | 42 | /** @var string root_path */ 43 | protected $root_path; 44 | 45 | /** @var string php_ext */ 46 | protected $php_ext; 47 | 48 | /** 49 | * Constructor 50 | * 51 | * @param \phpbb\user $user User object 52 | * @param \phpbb\user_loader $user_loader User loader object 53 | * @param \phpbb\language\language $language Language object 54 | * @param \phpbb\template\template $template Template object 55 | * @param \phpbb\log\log $log The phpBB log system 56 | * @param \phpbb\ads\ad\manager $manager Ad manager object 57 | * @param \phpbb\ads\location\manager $location_manager Template location manager object 58 | * @param \phpbb\group\helper $group_helper Group helper object 59 | * @param string $root_path phpBB root path 60 | * @param string $php_ext PHP extension 61 | */ 62 | public function __construct(\phpbb\user $user, \phpbb\user_loader $user_loader, \phpbb\language\language $language, \phpbb\template\template $template, \phpbb\log\log $log, \phpbb\ads\ad\manager $manager, \phpbb\ads\location\manager $location_manager, \phpbb\group\helper $group_helper, $root_path, $php_ext) 63 | { 64 | $this->user = $user; 65 | $this->user_loader = $user_loader; 66 | $this->language = $language; 67 | $this->template = $template; 68 | $this->log = $log; 69 | $this->location_manager = $location_manager; 70 | $this->manager = $manager; 71 | $this->group_helper = $group_helper; 72 | $this->root_path = $root_path; 73 | $this->php_ext = $php_ext; 74 | } 75 | 76 | /** 77 | * Assign ad data for ACP form template. 78 | * 79 | * @param array $data Ad data 80 | * @param array $errors Validation errors 81 | */ 82 | public function assign_data($data, $errors) 83 | { 84 | $this->assign_locations($data['ad_locations']); 85 | $this->assign_groups(($data['ad_id'] ?? 0), ($data['ad_groups'] ?? array())); 86 | 87 | $errors = array_map(array($this->language, 'lang'), $errors); 88 | $this->template->assign_vars(array( 89 | 'S_ERROR' => (bool) count($errors), 90 | 'ERROR_MSG' => count($errors) ? implode('
', $errors) : '', 91 | 92 | 'AD_NAME' => $data['ad_name'], 93 | 'AD_NOTE' => $data['ad_note'], 94 | 'AD_CODE' => $data['ad_code'], 95 | 'AD_ENABLED' => $data['ad_enabled'], 96 | 'AD_START_DATE' => $data['ad_start_date'], 97 | 'AD_END_DATE' => $data['ad_end_date'], 98 | 'AD_PRIORITY' => $data['ad_priority'], 99 | 'AD_CONTENT_ONLY' => $data['ad_content_only'], 100 | 'AD_VIEWS_LIMIT' => $data['ad_views_limit'], 101 | 'AD_CLICKS_LIMIT' => $data['ad_clicks_limit'], 102 | 'AD_OWNER' => $this->get_username($data['ad_owner']), 103 | 'AD_CENTERING' => $data['ad_centering'], 104 | )); 105 | } 106 | 107 | /** 108 | * Assign template locations data to the template. 109 | * 110 | * @param array $ad_locations The form data or nothing. 111 | * @return void 112 | */ 113 | public function assign_locations($ad_locations = array()) 114 | { 115 | foreach ($this->location_manager->get_all_locations() as $location_category_id => $location_category) 116 | { 117 | $this->template->assign_block_vars('ad_locations', array( 118 | 'CATEGORY_NAME' => $this->language->lang($location_category_id), 119 | )); 120 | 121 | foreach ($location_category as $location_id => $location_data) 122 | { 123 | $this->template->assign_block_vars('ad_locations', array( 124 | 'LOCATION_ID' => $location_id, 125 | 'LOCATION_DESC' => $location_data['desc'], 126 | 'LOCATION_NAME' => $location_data['name'], 127 | 'S_SELECTED' => in_array($location_id, $ad_locations), 128 | )); 129 | } 130 | } 131 | } 132 | 133 | /** 134 | * Assign groups data to the template. 135 | * 136 | * @param int $ad_id Advertisement ID 137 | * @param array $selected Array of selected groups from the form 138 | * @return void 139 | */ 140 | public function assign_groups($ad_id = 0, $selected = array()) 141 | { 142 | $groups = $this->manager->load_groups($ad_id); 143 | 144 | if (!$ad_id && count($selected)) 145 | { 146 | array_walk($groups, function (&$group) use ($selected) { 147 | $group['group_selected'] = in_array($group['group_id'], $selected); 148 | }); 149 | } 150 | 151 | foreach ($groups as $group) 152 | { 153 | $this->template->assign_block_vars('groups', array( 154 | 'ID' => $group['group_id'], 155 | 'NAME' => $this->group_helper->get_name($group['group_name']), 156 | 'S_SELECTED' => (bool) $group['group_selected'], 157 | )); 158 | } 159 | } 160 | 161 | /** 162 | * Log action 163 | * 164 | * @param string $action Performed action in uppercase 165 | * @param string $ad_name Advertisement name 166 | * @return void 167 | */ 168 | public function log($action, $ad_name) 169 | { 170 | $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'ACP_PHPBB_ADS_' . $action . '_LOG', time(), array($ad_name)); 171 | } 172 | 173 | /** 174 | * Get "Find username" URL to easily look for ad owner. 175 | * 176 | * @return string Find username URL 177 | */ 178 | public function get_find_username_link() 179 | { 180 | return append_sid("{$this->root_path}memberlist.{$this->php_ext}", 'mode=searchuser&form=acp_admanagement_add&field=ad_owner&select_single=true'); 181 | } 182 | 183 | /** 184 | * Is an ad expired? 185 | * 186 | * @param array $row Advertisement data 187 | * @return bool True if expired, false otherwise 188 | */ 189 | public function is_expired($row) 190 | { 191 | if ((int) $row['ad_end_date'] > 0 && (int) $row['ad_end_date'] < time()) 192 | { 193 | return true; 194 | } 195 | 196 | if ($row['ad_views_limit'] && $row['ad_views'] >= $row['ad_views_limit']) 197 | { 198 | return true; 199 | } 200 | 201 | if ($row['ad_clicks_limit'] && $row['ad_clicks'] >= $row['ad_clicks_limit']) 202 | { 203 | return true; 204 | } 205 | 206 | return false; 207 | } 208 | 209 | /** 210 | * Prepare ad owner for display. Method takes user_id 211 | * of the ad owner and returns username. 212 | * 213 | * @param int $user_id User ID 214 | * @return string Username belonging to $user_id. 215 | */ 216 | protected function get_username($user_id) 217 | { 218 | if (!$user_id) 219 | { 220 | return ''; 221 | } 222 | 223 | $this->user_loader->load_users(array($user_id)); 224 | return $this->user_loader->get_username($user_id, 'username'); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /controller/increment_controller.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\controller; 12 | 13 | /** 14 | * Increment controller 15 | */ 16 | class increment_controller 17 | { 18 | /** @var \phpbb\ads\ad\manager */ 19 | protected $manager; 20 | 21 | /** @var \phpbb\request\request */ 22 | protected $request; 23 | 24 | /** 25 | * Constructor 26 | * 27 | * @param \phpbb\ads\ad\manager $manager Advertisement manager object 28 | * @param \phpbb\request\request $request Request object 29 | */ 30 | public function __construct(\phpbb\ads\ad\manager $manager, \phpbb\request\request $request) 31 | { 32 | $this->manager = $manager; 33 | $this->request = $request; 34 | } 35 | 36 | /** 37 | * Handle request. 38 | * 39 | * @param mixed $data Ad ID or ad IDs 40 | * @param string $mode clicks or views 41 | * @return \Symfony\Component\HttpFoundation\JsonResponse A Symfony JsonResponse object 42 | * @throws \phpbb\exception\http_exception 43 | */ 44 | public function handle($data, $mode) 45 | { 46 | if (!empty($data) && $this->request->is_ajax()) 47 | { 48 | $this->{$mode}($data); 49 | 50 | return new \Symfony\Component\HttpFoundation\JsonResponse(); 51 | } 52 | 53 | throw new \phpbb\exception\http_exception(403, 'NOT_AUTHORISED'); 54 | } 55 | 56 | /** 57 | * Increment clicks for an ad. 58 | * 59 | * @param int $ad_id Advertisement ID 60 | */ 61 | protected function clicks($ad_id) 62 | { 63 | $this->manager->increment_ad_clicks($ad_id); 64 | } 65 | 66 | /** 67 | * Increment views for ads. 68 | * 69 | * @param string $ad_ids Advertisement IDs 70 | */ 71 | protected function views($ad_ids) 72 | { 73 | $this->manager->increment_ads_views(explode('-', $ad_ids)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /controller/ucp_controller.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\controller; 12 | 13 | /** 14 | * Front controller 15 | */ 16 | class ucp_controller 17 | { 18 | /** @var \phpbb\ads\ad\manager */ 19 | protected $manager; 20 | 21 | /** @var \phpbb\ads\controller\helper */ 22 | protected $helper; 23 | 24 | /** @var \phpbb\user */ 25 | protected $user; 26 | 27 | /** @var \phpbb\language\language */ 28 | protected $language; 29 | 30 | /** @var \phpbb\template\template */ 31 | protected $template; 32 | 33 | /** @var \phpbb\config\config */ 34 | protected $config; 35 | 36 | /** @var string Custom form action */ 37 | protected $u_action; 38 | 39 | /** 40 | * Constructor 41 | * 42 | * @param \phpbb\ads\ad\manager $manager Advertisement manager object 43 | * @param \phpbb\ads\controller\helper $helper Helper object 44 | * @param \phpbb\user $user User object 45 | * @param \phpbb\language\language $language Language object 46 | * @param \phpbb\template\template $template Template object 47 | * @param \phpbb\config\config $config Config object 48 | */ 49 | public function __construct(\phpbb\ads\ad\manager $manager, \phpbb\ads\controller\helper $helper, \phpbb\user $user, \phpbb\language\language $language, \phpbb\template\template $template, \phpbb\config\config $config) 50 | { 51 | $this->manager = $manager; 52 | $this->helper = $helper; 53 | $this->user = $user; 54 | $this->language = $language; 55 | $this->template = $template; 56 | $this->config = $config; 57 | } 58 | 59 | /** 60 | * @param string $u_action Action URL 61 | */ 62 | public function set_page_url($u_action) 63 | { 64 | $this->u_action = $u_action; 65 | } 66 | 67 | /** 68 | * Display UCP ads module 69 | */ 70 | public function main() 71 | { 72 | $this->language->add_lang('ucp', 'phpbb/ads'); 73 | 74 | foreach ($this->manager->get_ads_by_owner($this->user->data['user_id']) as $ad) 75 | { 76 | $ad_enabled = (int) $ad['ad_enabled']; 77 | $ad_expired = $this->helper->is_expired($ad); 78 | 79 | if ($ad_expired && $ad_enabled) 80 | { 81 | $ad_enabled = 0; 82 | $this->manager->update_ad($ad['ad_id'], array('ad_enabled' => 0)); 83 | } 84 | 85 | $this->template->assign_block_vars($ad_expired ? 'expired' : 'ads', array( 86 | 'NAME' => $ad['ad_name'], 87 | 'START_DATE' => $ad['ad_start_date'], 88 | 'END_DATE' => $ad['ad_end_date'], 89 | 'VIEWS' => $ad['ad_views'], 90 | 'VIEWS_LIMIT' => $ad['ad_views_limit'], 91 | 'CLICKS' => $ad['ad_clicks'], 92 | 'CLICKS_LIMIT' => $ad['ad_clicks_limit'], 93 | 'S_ENABLED' => $ad_enabled, 94 | )); 95 | } 96 | 97 | $this->template->assign_vars(array( 98 | 'S_VIEWS_ENABLED' => $this->config['phpbb_ads_enable_views'], 99 | 'S_CLICKS_ENABLED' => $this->config['phpbb_ads_enable_clicks'], 100 | )); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /controller/visual_demo_controller.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\controller; 12 | 13 | /** 14 | * Visual demo controller 15 | */ 16 | class visual_demo_controller 17 | { 18 | /** @var \phpbb\auth\auth */ 19 | protected $auth; 20 | 21 | /** @var \phpbb\config\config */ 22 | protected $config; 23 | 24 | /** @var \phpbb\request\request */ 25 | protected $request; 26 | 27 | /** @var \phpbb\user */ 28 | protected $user; 29 | 30 | /** @var string */ 31 | protected $root_path; 32 | 33 | /** @var string */ 34 | protected $php_ext; 35 | 36 | /** 37 | * Constructor 38 | * 39 | * @param \phpbb\auth\auth $auth 40 | * @param \phpbb\config\config $config 41 | * @param \phpbb\request\request $request 42 | * @param \phpbb\user $user 43 | * @param string $root_path 44 | * @param string $php_ext 45 | */ 46 | public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\request\request $request, \phpbb\user $user, $root_path, $php_ext) 47 | { 48 | $this->auth = $auth; 49 | $this->config = $config; 50 | $this->request = $request; 51 | $this->user = $user; 52 | $this->root_path = $root_path; 53 | $this->php_ext = $php_ext; 54 | } 55 | 56 | /** 57 | * Visual demo handler 58 | * 59 | * When called by an admin, add or remove the visual demo cookie 60 | * and direct them to an appropriate forum page to view. 61 | * 62 | * @param string $action enable|disable 63 | * @return \Symfony\Component\HttpFoundation\JsonResponse 64 | * @throws \phpbb\exception\http_exception http exception 65 | */ 66 | public function handle($action) 67 | { 68 | // Protect against unauthorised access 69 | if (!$this->auth->acl_get('a_')) 70 | { 71 | throw new \phpbb\exception\http_exception(403, 'NO_AUTH_OPERATION'); 72 | } 73 | 74 | if ($action === 'disable') 75 | { 76 | // Destroy our cookie and redirect user to previous page viewed. 77 | $this->user->set_cookie('phpbb_ads_visual_demo', '', 1); 78 | $redirect = $this->request->variable('redirect', $this->user->data['session_page']); 79 | } 80 | else 81 | { 82 | // Create our cookie and send user to the index page. 83 | $this->user->set_cookie('phpbb_ads_visual_demo', time(), 0); 84 | $redirect = "{$this->root_path}index.$this->php_ext"; 85 | } 86 | 87 | // Send a JSON response if an AJAX request was used 88 | if ($this->request->is_ajax()) 89 | { 90 | return new \Symfony\Component\HttpFoundation\JsonResponse(array( 91 | 'success' => true, 92 | )); 93 | } 94 | 95 | // Redirect user to a page 96 | $redirect = reapply_sid($redirect); 97 | redirect($redirect); 98 | 99 | // We shouldn't get here, but throw http exception just in case 100 | throw new \phpbb\exception\http_exception(500, 'GENERAL_ERROR'); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /event/main_listener.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\event; 12 | 13 | /** 14 | * @ignore 15 | */ 16 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; 17 | 18 | /** 19 | * Advertisement management Event listener. 20 | */ 21 | class main_listener implements EventSubscriberInterface 22 | { 23 | /** @var \phpbb\template\template */ 24 | protected $template; 25 | 26 | /** @var \phpbb\template\context */ 27 | protected $template_context; 28 | 29 | /** @var \phpbb\user */ 30 | protected $user; 31 | 32 | /** @var \phpbb\config\config */ 33 | protected $config; 34 | 35 | /** @var \phpbb\ads\ad\manager */ 36 | protected $manager; 37 | 38 | /** @var \phpbb\ads\location\manager */ 39 | protected $location_manager; 40 | 41 | /** @var \phpbb\controller\helper */ 42 | protected $controller_helper; 43 | 44 | /** @var \phpbb\request\request */ 45 | protected $request; 46 | 47 | /** @var \phpbb\cache\driver\driver_interface */ 48 | protected $cache; 49 | 50 | /** @var string */ 51 | protected $php_ext; 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | public static function getSubscribedEvents() 57 | { 58 | return array( 59 | 'core.permissions' => 'set_permissions', 60 | 'core.user_setup' => 'load_language_on_setup', 61 | 'core.page_footer_after' => array(array('setup_ads'), array('visual_demo')), 62 | 'core.page_header_after' => array(array('adblocker'), array('clicks')), 63 | 'core.delete_user_after' => 'remove_ad_owner', 64 | 'core.adm_page_header_after' => 'disable_xss_protection', 65 | 'core.group_add_user_after' => 'destroy_user_group_cache', 66 | 'core.group_delete_user_after' => 'destroy_user_group_cache', 67 | ); 68 | } 69 | 70 | /** 71 | * Constructor 72 | * 73 | * @param \phpbb\template\template $template Template object 74 | * @param \phpbb\template\context $template_context Template context object 75 | * @param \phpbb\user $user User object 76 | * @param \phpbb\config\config $config Config object 77 | * @param \phpbb\ads\ad\manager $manager Advertisement manager object 78 | * @param \phpbb\ads\location\manager $location_manager Template location manager object 79 | * @param \phpbb\controller\helper $controller_helper Controller helper object 80 | * @param \phpbb\request\request $request Request object 81 | * @param \phpbb\cache\driver\driver_interface $cache Cache driver object 82 | * @param string $php_ext PHP extension 83 | */ 84 | public function __construct(\phpbb\template\template $template, \phpbb\template\context $template_context, \phpbb\user $user, \phpbb\config\config $config, \phpbb\ads\ad\manager $manager, \phpbb\ads\location\manager $location_manager, \phpbb\controller\helper $controller_helper, \phpbb\request\request $request, \phpbb\cache\driver\driver_interface $cache, $php_ext) 85 | { 86 | $this->template = $template; 87 | $this->template_context = $template_context; 88 | $this->user = $user; 89 | $this->config = $config; 90 | $this->manager = $manager; 91 | $this->location_manager = $location_manager; 92 | $this->controller_helper = $controller_helper; 93 | $this->request = $request; 94 | $this->cache = $cache; 95 | $this->php_ext = $php_ext; 96 | } 97 | 98 | /** 99 | * Wire up u_phpbb_ads permission 100 | * 101 | * @param \phpbb\event\data $event The event object 102 | * @return void 103 | */ 104 | public function set_permissions($event) 105 | { 106 | $event->update_subarray('permissions', 'u_phpbb_ads', ['lang' => 'ACL_U_PHPBB_ADS', 'cat' => 'misc']); 107 | $event->update_subarray('permissions', 'a_phpbb_ads_m', ['lang' => 'ACL_A_PHPBB_ADS_M', 'cat' => 'misc']); 108 | $event->update_subarray('permissions', 'a_phpbb_ads_s', ['lang' => 'ACL_A_PHPBB_ADS_S', 'cat' => 'misc']); 109 | } 110 | 111 | /** 112 | * Load common language file during user setup 113 | * 114 | * @param \phpbb\event\data $event The event object 115 | * @return void 116 | */ 117 | public function load_language_on_setup($event) 118 | { 119 | $lang_set_ext = $event['lang_set_ext']; 120 | $lang_set_ext[] = array( 121 | 'ext_name' => 'phpbb/ads', 122 | 'lang_set' => 'common', 123 | ); 124 | $event['lang_set_ext'] = $lang_set_ext; 125 | } 126 | 127 | /** 128 | * Displays advertisements 129 | * 130 | * @return void 131 | */ 132 | public function setup_ads() 133 | { 134 | // Reason we access template's root ref is to check for existence 135 | // of 'MESSAGE_TEXT', which signals error page. 136 | $rootref = $this->template_context->get_root_ref(); 137 | $non_content_page = !empty($rootref['MESSAGE_TEXT']) || $this->is_non_content_page(); 138 | $location_ids = $this->location_manager->get_all_location_ids(); 139 | $user_groups = $this->manager->load_memberships($this->user->data['user_id']); 140 | $ad_ids = array(); 141 | 142 | foreach ($this->manager->get_ads($location_ids, $user_groups, $non_content_page) as $row) 143 | { 144 | $ad_ids[] = $row['ad_id']; 145 | 146 | $this->template->assign_vars(array( 147 | 'AD_' . strtoupper($row['location_id']) => htmlspecialchars_decode($row['ad_code'], ENT_COMPAT), 148 | 'AD_' . strtoupper($row['location_id']) . '_ID' => (int) $row['ad_id'], 149 | 'AD_' . strtoupper($row['location_id']) . '_CENTER' => (bool) $row['ad_centering'], 150 | )); 151 | } 152 | 153 | $this->views($ad_ids); 154 | } 155 | 156 | /** 157 | * Display Ad blocker friendly message if allowed 158 | * 159 | * @return void 160 | */ 161 | public function adblocker() 162 | { 163 | $this->template->assign_var('S_DISPLAY_ADBLOCKER', (int) $this->config['phpbb_ads_adblocker_message']); 164 | } 165 | 166 | /** 167 | * Add click tracking template variables 168 | * 169 | * @return void 170 | */ 171 | public function clicks() 172 | { 173 | if ($this->config['phpbb_ads_enable_clicks']) 174 | { 175 | $this->template->assign_vars(array( 176 | 'U_PHPBB_ADS_CLICK' => $this->controller_helper->route('phpbb_ads_click', array('data' => 0), true, ''), 177 | 'S_PHPBB_ADS_ENABLE_CLICKS' => true, 178 | )); 179 | } 180 | } 181 | 182 | /** 183 | * Generate visual demo templates 184 | * 185 | * @return void 186 | */ 187 | public function visual_demo() 188 | { 189 | if ($this->request->is_set($this->config['cookie_name'] . '_phpbb_ads_visual_demo', \phpbb\request\request_interface::COOKIE)) 190 | { 191 | $all_locations = $this->location_manager->get_all_locations(false); 192 | foreach ($this->location_manager->get_all_location_ids() as $location_id) 193 | { 194 | $this->template->assign_vars(array( 195 | 'AD_' . strtoupper($location_id) . '_ID' => $location_id, 196 | 'AD_' . strtoupper($location_id) => '
' . $all_locations[$location_id]['name'] . '
', 197 | )); 198 | } 199 | 200 | $this->template->assign_vars(array( 201 | 'S_PHPBB_ADS_VISUAL_DEMO' => true, 202 | 'U_DISABLE_VISUAL_DEMO' => $this->controller_helper->route('phpbb_ads_visual_demo', array('action' => 'disable')), 203 | )); 204 | } 205 | } 206 | 207 | /** 208 | * Prepare views counter template 209 | * 210 | * @param array $ad_ids List of ads that will be displayed on current request's page 211 | * @return void 212 | */ 213 | protected function views($ad_ids) 214 | { 215 | if ($this->config['phpbb_ads_enable_views'] && empty($this->user->data['is_bot']) && count($ad_ids)) 216 | { 217 | $this->template->assign_vars(array( 218 | 'S_INCREMENT_VIEWS' => true, 219 | 'U_PHPBB_ADS_VIEWS' => $this->controller_helper->route('phpbb_ads_view', array('data' => implode('-', $ad_ids)), true, ''), 220 | )); 221 | } 222 | } 223 | 224 | /** 225 | * Disable XSS Protection 226 | * In Chrome browsers, previewing an Ad Code with javascript can 227 | * be blocked, due to a false positive where Chrome thinks the 228 | * javascript is an XSS injection. This will temporarily disable 229 | * XSS protection in chrome while managing ads in the ACP. 230 | * 231 | * @param \phpbb\event\data $event The event object 232 | */ 233 | public function disable_xss_protection($event) 234 | { 235 | if (stripos($this->user->browser, 'chrome') !== false && 236 | stripos($this->user->page['page'], 'phpbb-ads') !== false) 237 | { 238 | $event['http_headers'] = array_merge($event['http_headers'], ['X-XSS-Protection' => '0']); 239 | } 240 | } 241 | 242 | /** 243 | * Remove ad owner when deleting user(s) 244 | * 245 | * @param \phpbb\event\data $event The event object 246 | * @return void 247 | */ 248 | public function remove_ad_owner($event) 249 | { 250 | $this->manager->remove_ad_owner($event['user_ids']); 251 | } 252 | 253 | /** 254 | * Destroy user_group cache after user was removed from the group. 255 | * 256 | * @return void 257 | */ 258 | public function destroy_user_group_cache() 259 | { 260 | $this->cache->destroy('sql', USER_GROUP_TABLE); 261 | } 262 | 263 | /** 264 | * Check if the page user is currently on is a non-content page. 265 | * This should include member list and details pages, posting and 266 | * replying pages, anything inside the UCP, MCP and ACP. 267 | * 268 | * @return bool True or false 269 | */ 270 | protected function is_non_content_page() 271 | { 272 | return count(array_intersect([$this->user->page['page_name'], $this->user->page['page_dir']], [ 273 | 'memberlist.' . $this->php_ext, 274 | 'viewonline.' . $this->php_ext, 275 | 'posting.' . $this->php_ext, 276 | 'ucp.' . $this->php_ext, 277 | 'mcp.' . $this->php_ext, 278 | 'adm', 279 | ])) > 0; 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /ext.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads; 12 | 13 | class ext extends \phpbb\extension\base 14 | { 15 | public const DATE_FORMAT = 'Y-m-d'; 16 | public const MAX_NAME_LENGTH = 255; 17 | public const DEFAULT_PRIORITY = 5; 18 | public const AD_BLOCK_MODES = [0, 1, 2]; 19 | 20 | /** 21 | * {@inheritdoc} 22 | * 23 | * Requires phpBB 3.3.2 due to using role_exists check in permission migration. 24 | */ 25 | public function is_enableable() 26 | { 27 | return phpbb_version_compare(PHPBB_VERSION, '3.3.2', '>=') 28 | && phpbb_version_compare(PHPBB_VERSION, '4.0.0-dev', '<'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /language/en/acp.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | if (!defined('IN_PHPBB')) 12 | { 13 | exit; 14 | } 15 | 16 | if (empty($lang) || !is_array($lang)) 17 | { 18 | $lang = array(); 19 | } 20 | 21 | $lang = array_merge($lang, array( 22 | // Manage ads 23 | 'AD_SETTINGS' => 'Advertisement settings', 24 | 'ACTIVE_ADS' => 'Active ads', 25 | 'EXPIRED_ADS' => 'Expired ads', 26 | 'STATUS' => 'Status', 27 | 'AD_NAME' => 'Name', 28 | 'AD_NAME_EXPLAIN' => 'The name is only used to help you identify this advertisement.', 29 | 'AD_ENABLED' => 'Enabled', 30 | 'AD_ENABLED_EXPLAIN' => 'If disabled, this advertisement will not be displayed.', 31 | 'AD_NOTE' => 'Notes', 32 | 'AD_NOTE_EXPLAIN' => 'Enter any notes for this advertisement. These notes are not shown anywhere except in the ACP and are optional.', 33 | 'AD_CODE' => 'Code', 34 | 'AD_CODE_EXPLAIN' => 'Enter the advertisement code here. All code must use HTML markup, BBCodes are not supported.', 35 | 'ANALYSE_AD_CODE' => 'Analyse advertisement code', 36 | 'EVERYTHING_OK' => 'The code appears OK.', 37 | 'AD_BANNER' => 'Advertisement banner', 38 | 'BANNER' => 'Upload a banner', 39 | 'BANNER_EXPLAIN' => 'You may upload an image in JPG, GIF or PNG format. The image will be stored in phpBB‘s images directory and an HTML IMG tag for the image will automatically be inserted into the ad code field.', 40 | 'BANNER_UPLOAD' => 'Upload banner', 41 | 'AD_PLACEMENT' => 'Advertisement placement', 42 | 'AD_LOCATIONS' => 'Locations', 43 | 'AD_LOCATIONS_EXPLAIN' => 'Select locations where you want this advertisement displayed. Mouse over a location for a short description of it. If multiple ads use the same location, one ad will be randomly selected to display in that location each time. Use CTRL+CLICK (or CMD+CLICK on Mac) to select/deselect more than one location.', 44 | 'AD_LOCATIONS_VISUAL_DEMO' => 'Start visual demo of ad locations', 45 | 'VISUAL_DEMO_EXPLAIN' => 'Start the visual demo to open your forum in a new browser window with sample ads in every location. Only you will see the demo, your visitors will see your forum normally. You must deactivate the demo when you are done viewing it (or it will persist for you as you use your forum). The “Click to disable visual demo” button will be available on every page.', 46 | 'AD_PRIORITY' => 'Priority', 47 | 'AD_PRIORITY_EXPLAIN' => 'Set a number between 1 and 10. Advertisements with higher number will be displayed more often when there are multiple ads using the same location.', 48 | 'AD_CONTENT_ONLY' => 'Display on content pages only', 49 | 'AD_CONTENT_ONLY_EXPLAIN' => 'This ad will only display on pages that contain content. It will not be shown on pages such as the UCP, login, registration, posting, replying, etc. Some advertising platforms (e.g. Google AdSense) require this.', 50 | 'AD_OPTIONS' => 'Advertisement options', 51 | 'AD_OWNER' => 'Owner', 52 | 'AD_OWNER_EXPLAIN' => 'Assigning an ad owner will give one of your board members permission to view this advertisement‘s view and click statistics in their User Control Panel. Leave this field blank to not assign an ad owner.', 53 | 'AD_VIEWS' => 'Views', 54 | 'AD_VIEWS_LIMIT' => 'Views Limit', 55 | 'AD_VIEWS_LIMIT_EXPLAIN' => 'Set the maximum number of times the ad will be displayed, after which the ad will no longer be displayed. Set 0 for unlimited views.', 56 | 'AD_CLICKS' => 'Clicks', 57 | 'AD_CLICKS_LIMIT' => 'Clicks Limit', 58 | 'AD_CLICKS_LIMIT_EXPLAIN' => 'Set the maximum number of times the ad will be clicked, after which the ad will no longer be displayed. Set 0 for unlimited clicks.', 59 | 'AD_START_DATE' => 'Start Date', 60 | 'AD_START_DATE_EXPLAIN' => 'Set the date the advertisement will start and become enabled. Leave this field blank if you do not want the advertisement to start automatically in the future. Please use YYYY-MM-DD format.', 61 | 'AD_END_DATE' => 'End Date', 62 | 'AD_END_DATE_EXPLAIN' => 'Set the date the advertisement will expire and become disabled. Leave this field blank if you do not want the advertisement to expire. Please use YYYY-MM-DD format.', 63 | 'AD_CENTERING' => 'Center this ad automatically', 64 | 'AD_CENTERING_EXPLAIN' => 'Set to yes to let this extension center your ad automatically. If this leads to undesired results, use CSS directly in the code to center your ad accordingly.', 65 | 66 | 'AD_PREVIEW' => 'Preview this advertisement', 67 | 'AD_ENABLE_TITLE' => array( // Plural rule doesn't apply here! Just translate the values. 68 | 0 => 'Click to enable', 69 | 1 => 'Click to disable', 70 | ), 71 | 'AD_EXPIRED_EXPLAIN' => 'This advertisement has expired and has been disabled.', 72 | 'ACP_ADS_EMPTY' => 'No advertisements to display. Add one using the button below.', 73 | 'ACP_ADS_ADD' => 'Add new advertisement', 74 | 'ACP_ADS_EDIT' => 'Edit advertisement', 75 | 76 | 'AD_NAME_REQUIRED' => 'Name is required.', 77 | 'AD_NAME_TOO_LONG' => 'Name length is limited to %d characters.', 78 | 'AD_CODE_ILLEGAL_CHARS' => 'Ad code contains the following unsupported characters: %s', 79 | 'AD_START_DATE_INVALID' => 'The start date is invalid or has already expired.', 80 | 'AD_END_DATE_INVALID' => 'The end date is invalid or has already expired.', 81 | 'AD_PRIORITY_INVALID' => 'The priority is invalid. Please set a number between 1 and 10.', 82 | 'AD_VIEWS_LIMIT_INVALID' => 'The views limit is invalid. Please set a non-negative number.', 83 | 'AD_CLICKS_LIMIT_INVALID' => 'The clicks limit is invalid. Please set a non-negative number.', 84 | 'AD_OWNER_INVALID' => 'The ad owner is invalid. Please select a user using the Find a member link.', 85 | 'NO_FILE_SELECTED' => 'No file selected.', 86 | 'CANNOT_CREATE_DIRECTORY' => 'The phpbb_ads directory could not be created. Please make sure the /images directory is writable.', 87 | 'FILE_MOVE_UNSUCCESSFUL' => 'Unable to move file to images/phpbb_ads.', 88 | 'END_DATE_TOO_SOON' => 'End date is sooner than start date.', 89 | 'ACP_AD_DOES_NOT_EXIST' => 'The advertisement does not exist.', 90 | 'ACP_AD_ADD_SUCCESS' => 'Advertisement added successfully.', 91 | 'ACP_AD_EDIT_SUCCESS' => 'Advertisement edited successfully.', 92 | 'ACP_AD_DELETE_SUCCESS' => 'Advertisement deleted successfully.', 93 | 'ACP_AD_DELETE_ERRORED' => 'There was an error deleting the advertisement.', 94 | 'ACP_AD_ENABLE_SUCCESS' => 'Advertisement enabled successfully.', 95 | 'ACP_AD_ENABLE_ERRORED' => 'There was an error enabling the advertisement.', 96 | 'ACP_AD_DISABLE_SUCCESS' => 'Advertisement disabled successfully.', 97 | 'ACP_AD_DISABLE_ERRORED' => 'There was an error disabling the advertisement.', 98 | 99 | // Analyser tests 100 | 'UNSECURE_CONNECTION' => 'Mixed Content
Your board runs on a secure HTTPS connection, however the ad code is attempting to load content from an insecure HTTP connection. This can cause browsers to generate a “Mixed Content” warning to let users know that the page contains insecure resources.', 101 | 'SCRIPT_WITHOUT_ASYNC' => 'Non-asynchronous javascript
This ad code loads JavaScript code in a non-asynchronous way. This means it will block any other Javascript from loading until it has completed loading, which can affect page load performance. Use of the async attribute can speed up the page load.', 102 | 'ALERT_USAGE' => 'Usage of alert()
Your code uses the alert() function which is not a good practice and can distract users. Some browsers may also block page load and display additional warnings to the user.', 103 | 'LOCATION_CHANGE' => 'Redirection
Your code appears it can redirect user to another page or site. Redirects can sometimes send users to unintended, often malicious, destinations. Please verify the integrity of your ad code’s redirection destination.', 104 | 105 | // Template location categories 106 | 'CAT_TOP_OF_PAGE' => 'Top of page', 107 | 'CAT_BOTTOM_OF_PAGE' => 'Bottom of page', 108 | 'CAT_IN_POSTS' => 'In posts', 109 | 'CAT_OTHER' => 'Other', 110 | 'CAT_INTERACTIVE' => 'Interactive', 111 | 'CAT_SPECIAL' => 'Special', 112 | 113 | // Settings 114 | 'ADBLOCKER_LEGEND' => 'Ad Blockers', 115 | 'ADBLOCKER_MESSAGE' => 'Ad blocker detected message', 116 | 'ADBLOCKER_MESSAGE_EXPLAIN' => 'Display a message to visitors using ad blockers, asking or requiring them to disable ad blocking on this forum. If requiring visitors to disable ad blockers, they will not be able to use the forum until they have disabled their ad blocker.', 117 | 'ADBLOCKER_MODES' => [ 118 | 0 => 'Allow ad blockers', 119 | 1 => 'Ask visitors to disable ad blockers', 120 | 2 => 'Require visitors to disable ad blockers', 121 | ], 122 | 'CLICKS_VIEWS_LEGEND' => 'Statistics and Tracking', 123 | 'ENABLE_VIEWS' => 'Count views', 124 | 'ENABLE_VIEWS_EXPLAIN' => 'This will enable counting how many times every ad has been displayed. Note, that it adds extra load to the server, so if you do not need this feature, disable it.', 125 | 'ENABLE_CLICKS' => 'Count clicks', 126 | 'ENABLE_CLICKS_EXPLAIN' => 'This will enable counting how many times every ad has been clicked. Note, that it adds extra load to the server, so if you do not need this feature, disable it.', 127 | 'HIDE_GROUPS' => 'Hide advertisement for groups', 128 | 'HIDE_GROUPS_EXPLAIN' => 'Members of selected groups will not see this advertisement. Use CTRL+CLICK (or CMD+CLICK on Mac) to select/deselect more than one group.', 129 | 130 | 'ACP_AD_SETTINGS_SAVED' => 'Advertisement management settings saved.', 131 | )); 132 | -------------------------------------------------------------------------------- /language/en/common.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | if (!defined('IN_PHPBB')) 12 | { 13 | exit; 14 | } 15 | 16 | if (empty($lang) || !is_array($lang)) 17 | { 18 | $lang = array(); 19 | } 20 | 21 | $lang = array_merge($lang, array( 22 | 'ADBLOCKER_TITLE' => 'Ad blocker detected', 23 | 'ADBLOCKER_MESSAGE' => [ 24 | 1 => 'Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker on our website.', 25 | 2 => 'Our website is made possible by displaying online advertisements to our visitors. Disable your ad blocker to continue using our website.', 26 | ], 27 | 'ADVERTISEMENT' => 'Advertisement', 28 | 'HIDE_AD' => 'Hide advertisement', 29 | 30 | 'VISUAL_DEMO' => 'Visual demo for ad locations is active', 31 | 'DISABLE_VISUAL_DEMO' => 'Click to disable visual demo', 32 | 'DISABLE_VISUAL_DEMO_ERROR' => 'There was a problem completing your request. Please try to disable the visual demo again.', 33 | 34 | // Template locations 35 | 'AD_ABOVE_HEADER' => 'Above header', 36 | 'AD_ABOVE_HEADER_DESC' => 'Displays on every page before the page header.', 37 | 'AD_BELOW_HEADER' => 'Below header', 38 | 'AD_BELOW_HEADER_DESC' => 'Displays on every page after the page header (and before navbar).', 39 | 'AD_BEFORE_POSTS' => 'Before posts', 40 | 'AD_BEFORE_POSTS_DESC' => 'Displays on topic page before the first post.', 41 | 'AD_AFTER_POSTS' => 'After posts', 42 | 'AD_AFTER_POSTS_DESC' => 'Displays on topic page after the last post (and also after Quick Reply if it’s enabled).', 43 | 'AD_BEFORE_QUICKREPLY' => 'Before Quick Reply', 44 | 'AD_BEFORE_QUICKREPLY_DESC' => 'Displays on topic page before the Quick Reply editor.', 45 | 'AD_AFTER_QUICKREPLY' => 'After Quick Reply', 46 | 'AD_AFTER_QUICKREPLY_DESC' => 'Displays on topic page after the Quick Reply editor.', 47 | 'AD_BELOW_FOOTER' => 'Below footer', 48 | 'AD_BELOW_FOOTER_DESC' => 'Displays on every page after the page footer.', 49 | 'AD_ABOVE_FOOTER' => 'Above footer', 50 | 'AD_ABOVE_FOOTER_DESC' => 'Displays on every page before the page footer.', 51 | 'AD_AFTER_FIRST_POST' => 'After first post', 52 | 'AD_AFTER_FIRST_POST_DESC' => 'Displays on topic page after the first post.', 53 | 'AD_AFTER_NOT_FIRST_POST' => 'After every post except first', 54 | 'AD_AFTER_NOT_FIRST_POST_DESC' => 'Displays on topic page after every post except the first post.', 55 | 'AD_BEFORE_PROFILE' => 'Before user profile', 56 | 'AD_BEFORE_PROFILE_DESC' => 'Displays before member profile page content.', 57 | 'AD_AFTER_PROFILE' => 'After user profile', 58 | 'AD_AFTER_PROFILE_DESC' => 'Displays after member profile page content.', 59 | 'AD_AFTER_HEADER_NAVBAR' => 'After header navbar', 60 | 'AD_AFTER_HEADER_NAVBAR_DESC' => 'Displays on every page after header navigation bar.', 61 | 'AD_AFTER_FOOTER_NAVBAR' => 'After footer navbar', 62 | 'AD_AFTER_FOOTER_NAVBAR_DESC' => 'Displays on every page after footer navigation bar.', 63 | 'AD_POP_UP' => 'Pop-up', 64 | 'AD_POP_UP_DESC' => 'Displays once per day when user visits this board as overlaying box. User need to close this box to continue to the content. Please, be aware, that this kind of advertisement is very obtrusive to the user! This location does not support JavaScript code.', 65 | 'AD_SLIDE_UP' => 'Slide up', 66 | 'AD_SLIDE_UP_DESC' => 'Displays on every page after user scrolls below main content. Slides up from the bottom.', 67 | 'AD_SCRIPTS' => 'Scripts', 68 | 'AD_SCRIPTS_DESC' => 'This location is for specialty JavaScript code like AdSense Auto ads, tracking codes, etc. The code entered here will be inserted into the page’s HEAD tag and is not intended for ad placement, but only for helper scripts.', 69 | )); 70 | -------------------------------------------------------------------------------- /language/en/info_acp_phpbb_ads.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | if (!defined('IN_PHPBB')) 12 | { 13 | exit; 14 | } 15 | 16 | if (empty($lang) || !is_array($lang)) 17 | { 18 | $lang = array(); 19 | } 20 | 21 | $lang = array_merge($lang, array( 22 | 'ACP_PHPBB_ADS_TITLE' => 'Advertisement Management', 23 | 'ACP_MANAGE_ADS_TITLE' => 'Manage advertisements', 24 | 'ACP_ADS_SETTINGS_TITLE' => 'Settings', 25 | 26 | 'ACP_PHPBB_ADS_ADD_LOG' => 'Advertisement added
» %s', 27 | 'ACP_PHPBB_ADS_EDIT_LOG' => 'Advertisement edited
» %s', 28 | 'ACP_PHPBB_ADS_DELETE_LOG' => 'Advertisement deleted
» %s', 29 | )); 30 | -------------------------------------------------------------------------------- /language/en/info_ucp_phpbb_ads.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | if (!defined('IN_PHPBB')) 12 | { 13 | exit; 14 | } 15 | 16 | if (empty($lang) || !is_array($lang)) 17 | { 18 | $lang = array(); 19 | } 20 | 21 | $lang = array_merge($lang, array( 22 | 'UCP_PHPBB_ADS_TITLE' => 'My advertisements', 23 | 'UCP_PHPBB_ADS_STATS' => 'Statistics', 24 | )); 25 | -------------------------------------------------------------------------------- /language/en/permissions_ads.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | if (!defined('IN_PHPBB')) 12 | { 13 | exit; 14 | } 15 | 16 | if (empty($lang) || !is_array($lang)) 17 | { 18 | $lang = array(); 19 | } 20 | 21 | $lang = array_merge($lang, array( 22 | 'ACL_U_PHPBB_ADS' => 'Can view own advertisement management statistics', 23 | 'ACL_A_PHPBB_ADS_M' => 'Can manage phpBB Advertisement ads', 24 | 'ACL_A_PHPBB_ADS_S' => 'Can manage phpBB Advertisement settings', 25 | )); 26 | -------------------------------------------------------------------------------- /language/en/ucp.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | if (!defined('IN_PHPBB')) 12 | { 13 | exit; 14 | } 15 | 16 | if (empty($lang) || !is_array($lang)) 17 | { 18 | $lang = array(); 19 | } 20 | 21 | $lang = array_merge($lang, array( 22 | 'AD_NAME' => 'Name', 23 | 'AD_START_DATE' => 'Start Date', 24 | 'AD_END_DATE' => 'End Date', 25 | 'AD_VIEWS' => 'Views', 26 | 'AD_CLICKS' => 'Clicks', 27 | 'AD_STATUS' => 'Status', 28 | 'EXPIRED' => 'Expired', 29 | 'ACTIVE_ADS' => 'Active ads', 30 | 'EXPIRED_ADS' => 'Expired ads', 31 | 'NO_ADS' => 'You do not have any advertisements displayed on this board.', 32 | )); 33 | -------------------------------------------------------------------------------- /location/manager.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location; 12 | 13 | class manager 14 | { 15 | /** 16 | * Array that contains all available template location types which are passed 17 | * via the service container 18 | * @var array 19 | */ 20 | protected $template_locations; 21 | 22 | /** 23 | * Construct an template locations manager object 24 | * 25 | * @param array $template_locations Template location types passed via the service container 26 | */ 27 | public function __construct($template_locations) 28 | { 29 | $this->register_template_locations($template_locations); 30 | } 31 | 32 | /** 33 | * Get a list of all template location types 34 | * 35 | * If $with_categories is true, returns a composite associated array 36 | * of location category, ID, name and desc: 37 | * array( 38 | * location_category => array( 39 | * location_id => array( 40 | * 'name' => location_name 41 | * 'desc' => location_description 42 | * ), 43 | * ... 44 | * ), 45 | * ... 46 | * ) 47 | * 48 | * Otherwise returns only location ID, name and desc: 49 | * array( 50 | * location_id => array( 51 | * 'name' => location_name 52 | * 'desc' => location_description 53 | * ), 54 | * ... 55 | * ) 56 | * 57 | * @param bool $with_categories Should we organize locations into categories? 58 | * 59 | * @return array Array containing a list of all template locations sorted by categories 60 | */ 61 | public function get_all_locations($with_categories = true) 62 | { 63 | $location_types = array(); 64 | 65 | foreach ($this->template_locations as $location_category_id => $location_category) 66 | { 67 | foreach ($location_category as $id => $location_type) 68 | { 69 | $body = array( 70 | 'name' => $location_type->get_name(), 71 | 'desc' => $location_type->get_desc(), 72 | ); 73 | 74 | if ($with_categories) 75 | { 76 | $location_types[$location_category_id][$id] = $body; 77 | } 78 | else 79 | { 80 | $location_types[$id] = $body; 81 | } 82 | } 83 | } 84 | 85 | return $location_types; 86 | } 87 | 88 | /** 89 | * Get a list of all template location IDs for display 90 | * 91 | * @return array Array containing a list of all template location IDs 92 | */ 93 | public function get_all_location_ids() 94 | { 95 | $template_locations = array(); 96 | 97 | foreach ($this->template_locations as $location_category) 98 | { 99 | foreach ($location_category as $location_id => $location) 100 | { 101 | if ($location->will_display()) 102 | { 103 | $template_locations[] = $location_id; 104 | } 105 | } 106 | } 107 | 108 | return $template_locations; 109 | } 110 | 111 | /** 112 | * Register template locations 113 | * 114 | * @param array $template_locations Template location types passed via the service container 115 | */ 116 | protected function register_template_locations($template_locations) 117 | { 118 | if (!empty($template_locations)) 119 | { 120 | // Define categories here for custom ordering. 121 | // Static definition also prevents external location 122 | // types to use nondefined category. 123 | $this->template_locations = array( 124 | 'CAT_TOP_OF_PAGE' => array(), 125 | 'CAT_BOTTOM_OF_PAGE' => array(), 126 | 'CAT_IN_POSTS' => array(), 127 | 'CAT_OTHER' => array(), 128 | 'CAT_INTERACTIVE' => array(), 129 | 'CAT_SPECIAL' => array(), 130 | ); 131 | 132 | foreach ($template_locations as $location) 133 | { 134 | $this->template_locations[$location->get_category()][$location->get_id()] = $location; 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /location/type/above_footer.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class above_footer extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'above_footer'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_BOTTOM_OF_PAGE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /location/type/above_header.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class above_header extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'above_header'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_TOP_OF_PAGE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /location/type/after_first_post.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class after_first_post extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'after_first_post'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_IN_POSTS; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function will_display() 35 | { 36 | return strpos($this->user->page['page_name'], 'viewtopic') !== false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /location/type/after_footer_navbar.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class after_footer_navbar extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'after_footer_navbar'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_BOTTOM_OF_PAGE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /location/type/after_header_navbar.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class after_header_navbar extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'after_header_navbar'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_TOP_OF_PAGE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /location/type/after_not_first_post.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class after_not_first_post extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'after_not_first_post'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_IN_POSTS; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function will_display() 35 | { 36 | return strpos($this->user->page['page_name'], 'viewtopic') !== false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /location/type/after_posts.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class after_posts extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'after_posts'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_IN_POSTS; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function will_display() 35 | { 36 | return strpos($this->user->page['page_name'], 'viewtopic') !== false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /location/type/after_profile.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class after_profile extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'after_profile'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_OTHER; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function will_display() 35 | { 36 | return strpos($this->user->page['page_name'], 'memberlist') !== false && strpos($this->user->page['query_string'], 'viewprofile') !== false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /location/type/after_quickreply.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class after_quickreply extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'after_quickreply'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_IN_POSTS; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function will_display() 35 | { 36 | return strpos($this->user->page['page_name'], 'viewtopic') !== false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /location/type/base.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | /** 14 | * Base class for template location types 15 | */ 16 | abstract class base implements type_interface 17 | { 18 | /** 19 | * User object 20 | * @var \phpbb\user 21 | */ 22 | protected $user; 23 | 24 | /** 25 | * Language object 26 | * @var \phpbb\language\language 27 | */ 28 | protected $language; 29 | 30 | /** 31 | * Construct a template location object 32 | * 33 | * @param \phpbb\user $user User object 34 | * @param \phpbb\language\language $language Language object 35 | */ 36 | public function __construct(\phpbb\user $user, \phpbb\language\language $language) 37 | { 38 | $this->user = $user; 39 | $this->language = $language; 40 | } 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | public function get_name() 46 | { 47 | return $this->language->lang('AD_' . strtoupper($this->get_id())); 48 | } 49 | 50 | /** 51 | * {@inheritDoc} 52 | */ 53 | public function get_desc() 54 | { 55 | return $this->language->lang('AD_' . strtoupper($this->get_id()) . '_DESC'); 56 | } 57 | 58 | /** 59 | * {@inheritDoc} 60 | */ 61 | public function will_display() 62 | { 63 | return true; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /location/type/before_posts.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class before_posts extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'before_posts'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_IN_POSTS; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function will_display() 35 | { 36 | return strpos($this->user->page['page_name'], 'viewtopic') !== false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /location/type/before_profile.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class before_profile extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'before_profile'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_OTHER; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function will_display() 35 | { 36 | return strpos($this->user->page['page_name'], 'memberlist') !== false && strpos($this->user->page['query_string'], 'viewprofile') !== false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /location/type/before_quickreply.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class before_quickreply extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'before_quickreply'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_IN_POSTS; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function will_display() 35 | { 36 | return strpos($this->user->page['page_name'], 'viewtopic') !== false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /location/type/below_footer.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class below_footer extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'below_footer'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_BOTTOM_OF_PAGE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /location/type/below_header.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class below_header extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'below_header'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_TOP_OF_PAGE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /location/type/pop_up.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class pop_up extends base 14 | { 15 | /** @var \phpbb\request\request */ 16 | protected $request; 17 | /** @var \phpbb\config\config */ 18 | protected $config; 19 | /** @var \phpbb\template\template */ 20 | protected $template; 21 | 22 | /** 23 | * pop_up location constructor. 24 | * 25 | * @param \phpbb\user $user User object 26 | * @param \phpbb\language\language $language Language object 27 | * @param \phpbb\request\request $request Request object 28 | * @param \phpbb\config\config $config Config object 29 | * @param \phpbb\template\template $template Template object 30 | */ 31 | public function __construct(\phpbb\user $user, \phpbb\language\language $language, \phpbb\request\request $request, \phpbb\config\config $config, \phpbb\template\template $template) 32 | { 33 | parent::__construct($user, $language); 34 | 35 | $this->request = $request; 36 | $this->config = $config; 37 | $this->template = $template; 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | public function get_id() 44 | { 45 | return 'pop_up'; 46 | } 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | public function get_category() 52 | { 53 | return self::CAT_INTERACTIVE; 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | public function will_display() 60 | { 61 | if ($this->request->is_set($this->config['cookie_name'] . '_pop_up', \phpbb\request\request_interface::COOKIE)) 62 | { 63 | return false; 64 | } 65 | 66 | $this->template->assign_vars(array( 67 | 'POP_UP_COOKIE_NAME' => $this->config['cookie_name'] . '_pop_up', 68 | 'POP_UP_COOKIE_EXPIRES' => gmdate('D, d M Y H:i:s T', strtotime('+1 day')), 69 | 'POP_UP_COOKIE_PATH' => $this->config['cookie_path'], 70 | )); 71 | return true; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /location/type/scripts.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class scripts extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'scripts'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_SPECIAL; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /location/type/slide_up.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | class slide_up extends base 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function get_id() 19 | { 20 | return 'slide_up'; 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function get_category() 27 | { 28 | return self::CAT_INTERACTIVE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /location/type/type_interface.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\location\type; 12 | 13 | /** 14 | * Interface for template location types 15 | */ 16 | interface type_interface 17 | { 18 | const CAT_TOP_OF_PAGE = 'CAT_TOP_OF_PAGE'; 19 | const CAT_BOTTOM_OF_PAGE = 'CAT_BOTTOM_OF_PAGE'; 20 | const CAT_IN_POSTS = 'CAT_IN_POSTS'; 21 | const CAT_OTHER = 'CAT_OTHER'; 22 | const CAT_INTERACTIVE = 'CAT_INTERACTIVE'; 23 | const CAT_SPECIAL = 'CAT_SPECIAL'; 24 | 25 | /** 26 | * Returns the unique ID of the location. 27 | * 28 | * @return string ID of location. 29 | */ 30 | public function get_id(); 31 | 32 | /** 33 | * Returns the category of the location. 34 | * Possible categories are: 35 | * - Top of page (self::CAT_TOP_OF_PAGE) 36 | * - Bottom of page (self::CAT_BOTTOM_OF_PAGE) 37 | * - In posts (self::CAT_IN_POSTS) 38 | * - Other (self::CAT_OTHER) 39 | * - Interactive (self::CAT_INTERACTIVE) 40 | * - Special (self::CAT_SPECIAL) 41 | * 42 | * @return string ID of location. 43 | */ 44 | public function get_category(); 45 | 46 | /** 47 | * Returns the name of the location. 48 | * 49 | * @return string Name of location. 50 | */ 51 | public function get_name(); 52 | 53 | /** 54 | * Returns the description of the location. 55 | * 56 | * @return string Description of location. 57 | */ 58 | public function get_desc(); 59 | 60 | /** 61 | * Returns whether or not this location type will be displayed on a current page. 62 | * 63 | * Generally, you can always return true, but if you can narrow down the usage 64 | * without adding extra load to server, this will further enhance the extension's 65 | * performance. 66 | * 67 | * @return bool True when location type will be displayed on a current page and false if not. 68 | */ 69 | public function will_display(); 70 | } 71 | -------------------------------------------------------------------------------- /migrations/v10x/m10_ad_owner_schema.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m10_ad_owner_schema extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_column_exists($this->table_prefix . 'ads', 'ad_owner'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array( 29 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 30 | '\phpbb\ads\migrations\v10x\m4_indexes', 31 | '\phpbb\ads\migrations\v10x\m9_views_clicks', 32 | ); 33 | } 34 | 35 | /** 36 | * Add the ad owner to ads table 37 | * 38 | * @return array Array of table schema 39 | * @access public 40 | */ 41 | public function update_schema() 42 | { 43 | return array( 44 | 'add_columns' => array( 45 | $this->table_prefix . 'ads' => array( 46 | 'ad_owner' => array('UINT', 0), 47 | ), 48 | ), 49 | ); 50 | } 51 | 52 | /** 53 | * Drop the ad owner from ads table 54 | * 55 | * @return array Array of table schema 56 | * @access public 57 | */ 58 | public function revert_schema() 59 | { 60 | return array( 61 | 'drop_columns' => array( 62 | $this->table_prefix . 'ads' => array( 63 | 'ad_owner', 64 | ), 65 | ), 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /migrations/v10x/m11_ad_owner_data.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m11_ad_owner_data extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public static function depends_on() 19 | { 20 | return array( 21 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 22 | '\phpbb\ads\migrations\v10x\m10_ad_owner_schema', 23 | ); 24 | } 25 | 26 | /** 27 | * Add the UCP module and new permission 28 | * 29 | * @return array Array of data update instructions 30 | */ 31 | public function update_data() 32 | { 33 | return array( 34 | array('module.add', array( 35 | 'ucp', 36 | '', 37 | 'UCP_PHPBB_ADS_TITLE' 38 | )), 39 | array('module.add', array( 40 | 'ucp', 41 | 'UCP_PHPBB_ADS_TITLE', 42 | array( 43 | 'module_basename' => '\phpbb\ads\ucp\main_module', 44 | 'modes' => array('stats'), 45 | ), 46 | )), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /migrations/v10x/m12_u_phpbb_ads_permission.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m12_u_phpbb_ads_permission extends \phpbb\db\migration\container_aware_migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public static function depends_on() 19 | { 20 | return array( 21 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 22 | '\phpbb\ads\migrations\v10x\m10_ad_owner_schema', 23 | '\phpbb\ads\migrations\v10x\m11_ad_owner_data', 24 | ); 25 | } 26 | 27 | /** 28 | * Add new permission 29 | * 30 | * @return array Array of data update instructions 31 | */ 32 | public function update_data() 33 | { 34 | return array( 35 | array('permission.add', array('u_phpbb_ads')), 36 | array('custom', array(array($this, 'set_u_phpbb_ads_permission'))), 37 | array('custom', array(array($this, 'update_ucp_module_permission'))), 38 | ); 39 | } 40 | 41 | /** 42 | * Find existing ad owners and assign them the new u_phpbb_ads permission 43 | */ 44 | public function set_u_phpbb_ads_permission() 45 | { 46 | if (!class_exists('auth_admin')) 47 | { 48 | include($this->phpbb_root_path . 'includes/acp/auth.' . $this->php_ext); 49 | } 50 | $auth_admin = new \auth_admin(); 51 | 52 | $sql = 'SELECT ad_owner 53 | FROM ' . $this->table_prefix . 'ads 54 | WHERE ad_owner <> 0 55 | GROUP BY ad_owner'; 56 | $result = $this->db->sql_query($sql); 57 | while ($row = $this->db->sql_fetchrow($result)) 58 | { 59 | $auth_admin->acl_set('user', 0, $row['ad_owner'], array('u_phpbb_ads' => 1)); 60 | } 61 | $this->db->sql_freeresult($result); 62 | } 63 | 64 | /** 65 | * Update module auth manually, because "module.remove" tool causes problems when deleting extension. 66 | */ 67 | public function update_ucp_module_permission() 68 | { 69 | $sql = 'UPDATE ' . $this->container->getParameter('tables.modules') . " 70 | SET module_auth = 'ext_phpbb/ads && acl_u_phpbb_ads' 71 | WHERE module_langname = 'UCP_PHPBB_ADS_STATS'"; 72 | $this->db->sql_query($sql); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /migrations/v10x/m13_content_only.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m13_content_only extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_column_exists($this->table_prefix . 'ads', 'ad_content_only'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array( 29 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 30 | '\phpbb\ads\migrations\v10x\m4_indexes', 31 | ); 32 | } 33 | 34 | /** 35 | * Add the ad_content_only to ads table 36 | * 37 | * @return array Array of table schema 38 | * @access public 39 | */ 40 | public function update_schema() 41 | { 42 | return array( 43 | 'add_columns' => array( 44 | $this->table_prefix . 'ads' => array( 45 | 'ad_content_only' => array('BOOL', 0), 46 | ), 47 | ), 48 | 'add_index' => array( 49 | $this->table_prefix . 'ads' => array( 50 | 'ad_co' => array('ad_content_only'), // index used in ad\manager::get_ads 51 | ), 52 | ), 53 | ); 54 | } 55 | 56 | /** 57 | * Drop the ad_content_only from ads table 58 | * 59 | * @return array Array of table schema 60 | * @access public 61 | */ 62 | public function revert_schema() 63 | { 64 | return array( 65 | 'drop_keys' => array( 66 | $this->table_prefix . 'ads' => array( 67 | 'ad_co', 68 | ), 69 | ), 70 | 'drop_columns' => array( 71 | $this->table_prefix . 'ads' => array( 72 | 'ad_content_only', 73 | ), 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /migrations/v10x/m1_initial_schema.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | /** 14 | * Migration stage 1: Initial schema 15 | */ 16 | class m1_initial_schema extends \phpbb\db\migration\migration 17 | { 18 | /** 19 | * {@inheritDoc} 20 | */ 21 | public function effectively_installed() 22 | { 23 | return $this->db_tools->sql_table_exists($this->table_prefix . 'ads'); 24 | } 25 | 26 | /** 27 | * {@inheritDoc} 28 | */ 29 | public static function depends_on() 30 | { 31 | return array('\phpbb\db\migration\data\v31x\v316'); 32 | } 33 | 34 | /** 35 | * Add the ads table schema to the database: 36 | * ads: 37 | * ad_id 38 | * ad_name 39 | * ad_note 40 | * ad_code 41 | * ad_enabled 42 | * 43 | * @return array Array of table schema 44 | * @access public 45 | */ 46 | public function update_schema() 47 | { 48 | return array( 49 | 'add_tables' => array( 50 | $this->table_prefix . 'ads' => array( 51 | 'COLUMNS' => array( 52 | 'ad_id' => array('UINT', null, 'auto_increment'), 53 | 'ad_name' => array('VCHAR:255', ''), 54 | 'ad_note' => array('MTEXT_UNI', ''), 55 | 'ad_code' => array('TEXT_UNI', ''), 56 | 'ad_enabled' => array('BOOL', 0), 57 | ), 58 | 'PRIMARY_KEY' => 'ad_id', 59 | ), 60 | ), 61 | ); 62 | } 63 | 64 | /** 65 | * Drop the ads table schema from the database 66 | * 67 | * @return array Array of table schema 68 | * @access public 69 | */ 70 | public function revert_schema() 71 | { 72 | return array( 73 | 'drop_tables' => array( 74 | $this->table_prefix . 'ads', 75 | ), 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /migrations/v10x/m2_acp_module.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m2_acp_module extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | $sql = 'SELECT module_id 21 | FROM ' . $this->table_prefix . "modules 22 | WHERE module_class = 'acp' 23 | AND module_langname = 'ACP_PHPBB_ADS_TITLE'"; 24 | $result = $this->db->sql_query($sql); 25 | $module_id = (int) $this->db->sql_fetchfield('module_id'); 26 | $this->db->sql_freeresult($result); 27 | 28 | return $module_id; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public static function depends_on() 35 | { 36 | return array('\phpbb\ads\migrations\v10x\m1_initial_schema'); 37 | } 38 | 39 | /** 40 | * Add the ACP module 41 | * 42 | * @return array Array of data update instructions 43 | */ 44 | public function update_data() 45 | { 46 | return array( 47 | array('module.add', array( 48 | 'acp', 49 | 'ACP_CAT_DOT_MODS', 50 | 'ACP_PHPBB_ADS_TITLE' 51 | )), 52 | array('module.add', array( 53 | 'acp', 54 | 'ACP_PHPBB_ADS_TITLE', 55 | array( 56 | 'module_basename' => '\phpbb\ads\acp\main_module', 57 | 'modes' => array('manage'), 58 | ), 59 | )), 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /migrations/v10x/m3_template_locations_schema.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m3_template_locations_schema extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_table_exists($this->table_prefix . 'ad_locations'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array('\phpbb\ads\migrations\v10x\m1_initial_schema'); 29 | } 30 | 31 | /** 32 | * Add the ad_locations table schema to the database: 33 | * ad_locations: 34 | * ad_id 35 | * location_id 36 | * 37 | * @return array Array of table schema 38 | * @access public 39 | */ 40 | public function update_schema() 41 | { 42 | return array( 43 | 'add_tables' => array( 44 | $this->table_prefix . 'ad_locations' => array( 45 | 'COLUMNS' => array( 46 | 'ad_id' => array('UINT', 0), 47 | 'location_id' => array('VCHAR:255', ''), 48 | ), 49 | 'PRIMARY_KEY' => array('ad_id', 'location_id'), 50 | ), 51 | ), 52 | ); 53 | } 54 | 55 | /** 56 | * Drop the ad_locations table schema from the database 57 | * 58 | * @return array Array of table schema 59 | * @access public 60 | */ 61 | public function revert_schema() 62 | { 63 | return array( 64 | 'drop_tables' => array( 65 | $this->table_prefix . 'ad_locations', 66 | ), 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /migrations/v10x/m4_indexes.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m4_indexes extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_index_exists($this->table_prefix . 'ads', 'ad_enabled'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array( 29 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 30 | '\phpbb\ads\migrations\v10x\m3_template_locations_schema', 31 | ); 32 | } 33 | 34 | /** 35 | * Add the indexes 36 | * 37 | * @return array Array of altered table schema 38 | * @access public 39 | */ 40 | public function update_schema() 41 | { 42 | return array( 43 | 'add_index' => array( 44 | $this->table_prefix . 'ads' => array( 45 | 'ad_enabled' => array('ad_enabled'), // index used in ad\manager::get_ads 46 | ), 47 | $this->table_prefix . 'ad_locations' => array( 48 | 'location_id' => array('location_id'), // index used in ad\manager::get_ads 49 | ), 50 | ), 51 | ); 52 | } 53 | 54 | /** 55 | * Drop the indexes 56 | * 57 | * @return array Array of altered table schema 58 | * @access public 59 | */ 60 | public function revert_schema() 61 | { 62 | return array( 63 | 'drop_keys' => array( 64 | $this->table_prefix . 'ad_locations' => array( 65 | 'location_id', 66 | ), 67 | $this->table_prefix . 'ads' => array( 68 | 'ad_enabled', 69 | ), 70 | ), 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /migrations/v10x/m5_end_date.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m5_end_date extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_column_exists($this->table_prefix . 'ads', 'ad_end_date'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array( 29 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 30 | '\phpbb\ads\migrations\v10x\m4_indexes', 31 | ); 32 | } 33 | 34 | /** 35 | * Add the end date to ads table 36 | * 37 | * @return array Array of table schema 38 | * @access public 39 | */ 40 | public function update_schema() 41 | { 42 | return array( 43 | 'add_columns' => array( 44 | $this->table_prefix . 'ads' => array( 45 | 'ad_end_date' => array('TIMESTAMP', 0), 46 | ), 47 | ), 48 | ); 49 | } 50 | 51 | /** 52 | * Drop the end date from ads table 53 | * 54 | * @return array Array of table schema 55 | * @access public 56 | */ 57 | public function revert_schema() 58 | { 59 | return array( 60 | 'drop_columns' => array( 61 | $this->table_prefix . 'ads' => array( 62 | 'ad_end_date', 63 | ), 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /migrations/v10x/m6_hide_for_group.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m6_hide_for_group extends \phpbb\db\migration\container_aware_migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | $config_text = $this->container->get('config_text'); 21 | 22 | return $config_text->get('phpbb_ads_hide_groups') !== null; 23 | } 24 | 25 | /** 26 | * {@inheritDoc} 27 | */ 28 | public static function depends_on() 29 | { 30 | return array( 31 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 32 | '\phpbb\ads\migrations\v10x\m2_acp_module', 33 | ); 34 | } 35 | 36 | /** 37 | * Add the ACP settings module 38 | * 39 | * @return array Array of data update instructions 40 | */ 41 | public function update_data() 42 | { 43 | return array( 44 | array('config_text.add', array('phpbb_ads_hide_groups', '[]')), 45 | 46 | array('module.add', array( 47 | 'acp', 48 | 'ACP_PHPBB_ADS_TITLE', 49 | array( 50 | 'module_basename' => '\phpbb\ads\acp\main_module', 51 | 'modes' => array('settings'), 52 | ), 53 | )), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /migrations/v10x/m7_adblocker.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m7_adblocker extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->config->offsetExists('phpbb_ads_adblocker_message'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array('\phpbb\ads\migrations\v10x\m1_initial_schema'); 29 | } 30 | 31 | /** 32 | * Add phpbb_ads_adblocker_message config 33 | * 34 | * @return array Array of data update instructions 35 | */ 36 | public function update_data() 37 | { 38 | return array( 39 | array('config.add', array('phpbb_ads_adblocker_message', 0)), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /migrations/v10x/m8_priority.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m8_priority extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_column_exists($this->table_prefix . 'ads', 'ad_priority'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array( 29 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 30 | '\phpbb\ads\migrations\v10x\m4_indexes', 31 | ); 32 | } 33 | 34 | /** 35 | * Add the priority to ads table 36 | * 37 | * @return array Array of table schema 38 | * @access public 39 | */ 40 | public function update_schema() 41 | { 42 | return array( 43 | 'add_columns' => array( 44 | $this->table_prefix . 'ads' => array( 45 | 'ad_priority' => array('TINT:2', 5), 46 | ), 47 | ), 48 | ); 49 | } 50 | 51 | /** 52 | * Drop the priority from ads table 53 | * 54 | * @return array Array of table schema 55 | * @access public 56 | */ 57 | public function revert_schema() 58 | { 59 | return array( 60 | 'drop_columns' => array( 61 | $this->table_prefix . 'ads' => array( 62 | 'ad_priority', 63 | ), 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /migrations/v10x/m9_views_clicks.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v10x; 12 | 13 | class m9_views_clicks extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_column_exists($this->table_prefix . 'ads', 'ad_views'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array( 29 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 30 | '\phpbb\ads\migrations\v10x\m4_indexes', 31 | '\phpbb\ads\migrations\v10x\m5_end_date', 32 | '\phpbb\ads\migrations\v10x\m8_priority', 33 | ); 34 | } 35 | 36 | /** 37 | * Add the views and clicks to ads table 38 | * 39 | * @return array Array of table schema 40 | * @access public 41 | */ 42 | public function update_schema() 43 | { 44 | return array( 45 | 'add_columns' => array( 46 | $this->table_prefix . 'ads' => array( 47 | 'ad_views' => array('UINT', 0), 48 | 'ad_clicks' => array('UINT', 0), 49 | 'ad_views_limit' => array('UINT', 0), 50 | 'ad_clicks_limit' => array('UINT', 0), 51 | ), 52 | ), 53 | ); 54 | } 55 | 56 | /** 57 | * Drop the views and clicks from ads table 58 | * 59 | * @return array Array of table schema 60 | * @access public 61 | */ 62 | public function revert_schema() 63 | { 64 | return array( 65 | 'drop_columns' => array( 66 | $this->table_prefix . 'ads' => array( 67 | 'ad_views', 68 | 'ad_clicks', 69 | 'ad_views_limit', 70 | 'ad_clicks_limit', 71 | ), 72 | ), 73 | ); 74 | } 75 | 76 | /** 77 | * Add phpbb_ads_enable_views and phpbb_ads_enable_clicks config 78 | * 79 | * @return array Array of data update instructions 80 | */ 81 | public function update_data() 82 | { 83 | return array( 84 | array('config.add', array('phpbb_ads_enable_views', 0)), 85 | array('config.add', array('phpbb_ads_enable_clicks', 0)), 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /migrations/v20x/m1_hide_ad_for_group.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v20x; 12 | 13 | class m1_hide_ad_for_group extends \phpbb\db\migration\container_aware_migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_table_exists($this->table_prefix . 'ad_group'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array( 29 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 30 | '\phpbb\ads\migrations\v10x\m4_indexes', 31 | '\phpbb\ads\migrations\v10x\m6_hide_for_group', 32 | ); 33 | } 34 | 35 | /** 36 | * Add the ad_group table 37 | * 38 | * @return array Array of table schema 39 | * @access public 40 | */ 41 | public function update_schema() 42 | { 43 | return array( 44 | 'add_tables' => array( 45 | $this->table_prefix . 'ad_group' => array( 46 | 'COLUMNS' => array( 47 | 'ad_id' => array('UINT', 0), 48 | 'group_id' => array('UINT', 0), 49 | ), 50 | 'PRIMARY_KEY' => array('ad_id', 'group_id'), 51 | ), 52 | ), 53 | ); 54 | } 55 | 56 | /** 57 | * Drop the ad_group table 58 | * 59 | * @return array Array of table schema 60 | * @access public 61 | */ 62 | public function revert_schema() 63 | { 64 | return array( 65 | 'drop_tables' => array( 66 | $this->table_prefix . 'ad_group', 67 | ), 68 | ); 69 | } 70 | 71 | /** 72 | * Remove phpbb_ads_hide_groups config. 73 | * 74 | * @return array Array of data update instructions 75 | */ 76 | public function update_data() 77 | { 78 | return array( 79 | array('custom', array(array($this, 'convert_hide_groups'))), 80 | array('config_text.remove', array('phpbb_ads_hide_groups')), 81 | ); 82 | } 83 | 84 | /** 85 | * Convert hide_groups config value into rows in ad_group table 86 | */ 87 | public function convert_hide_groups() 88 | { 89 | $sql_ary = array(); 90 | 91 | $hide_groups = json_decode($this->container->get('config_text')->get('phpbb_ads_hide_groups'), true); 92 | $sql = 'SELECT ad_id 93 | FROM ' . $this->table_prefix . 'ads'; 94 | $result = $this->db->sql_query($sql); 95 | while ($row = $this->db->sql_fetchrow($result)) 96 | { 97 | foreach ($hide_groups as $group_id) 98 | { 99 | $sql_ary[] = array( 100 | 'ad_id' => $row['ad_id'], 101 | 'group_id' => $group_id, 102 | ); 103 | } 104 | } 105 | 106 | $this->db->sql_multi_insert($this->table_prefix . 'ad_group', $sql_ary); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /migrations/v20x/m2_centering_option.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v20x; 12 | 13 | class m2_centering_option extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_column_exists($this->table_prefix . 'ads', 'ad_centering'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return array( 29 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 30 | '\phpbb\ads\migrations\v10x\m4_indexes', 31 | ); 32 | } 33 | 34 | /** 35 | * Add the centering option to ads table 36 | * 37 | * @return array Array of table schema 38 | * @access public 39 | */ 40 | public function update_schema() 41 | { 42 | return array( 43 | 'add_columns' => array( 44 | $this->table_prefix . 'ads' => array( 45 | 'ad_centering' => array('BOOL', 1), 46 | ), 47 | ), 48 | ); 49 | } 50 | 51 | /** 52 | * Drop the centering option from ads table 53 | * 54 | * @return array Array of table schema 55 | * @access public 56 | */ 57 | public function revert_schema() 58 | { 59 | return array( 60 | 'drop_columns' => array( 61 | $this->table_prefix . 'ads' => array( 62 | 'ad_centering', 63 | ), 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /migrations/v20x/m3_add_start_date.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v20x; 12 | 13 | class m3_add_start_date extends \phpbb\db\migration\migration 14 | { 15 | /** 16 | * {@inheritDoc} 17 | */ 18 | public function effectively_installed() 19 | { 20 | return $this->db_tools->sql_column_exists($this->table_prefix . 'ads', 'ad_start_date'); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public static function depends_on() 27 | { 28 | return [ 29 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 30 | '\phpbb\ads\migrations\v10x\m4_indexes', 31 | ]; 32 | } 33 | 34 | /** 35 | * Add the start date option to ads table 36 | * 37 | * @return array Array of table schema 38 | * @access public 39 | */ 40 | public function update_schema() 41 | { 42 | return [ 43 | 'add_columns' => [ 44 | $this->table_prefix . 'ads' => [ 45 | 'ad_start_date' => ['TIMESTAMP', 0], 46 | ], 47 | ], 48 | ]; 49 | } 50 | 51 | /** 52 | * Drop the start date option from ads table 53 | * 54 | * @return array Array of table schema 55 | * @access public 56 | */ 57 | public function revert_schema() 58 | { 59 | return [ 60 | 'drop_columns' => [ 61 | $this->table_prefix . 'ads' => [ 62 | 'ad_start_date', 63 | ], 64 | ], 65 | ]; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /migrations/v20x/m4_admin_permission.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\migrations\v20x; 12 | 13 | /** 14 | * Migration stage 4: Add Admin Permission 15 | */ 16 | class m4_admin_permission extends \phpbb\db\migration\container_aware_migration 17 | { 18 | /** 19 | * {@inheritdoc 20 | */ 21 | public function effectively_installed() 22 | { 23 | $sql = 'SELECT * FROM ' . $this->table_prefix . "acl_options 24 | WHERE auth_option = 'a_phpbb_ads_m' OR auth_option = 'a_phpbb_ads_s'"; 25 | $result = $this->db->sql_query_limit($sql, 1); 26 | $row = $this->db->sql_fetchrow($result); 27 | $this->db->sql_freeresult($result); 28 | 29 | return $row !== false; 30 | } 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | public static function depends_on() 36 | { 37 | return [ 38 | '\phpbb\ads\migrations\v10x\m1_initial_schema', 39 | '\phpbb\ads\migrations\v10x\m2_acp_module', 40 | '\phpbb\ads\migrations\v20x\m3_add_start_date', 41 | ]; 42 | } 43 | 44 | /** 45 | * {@inheritDoc} 46 | */ 47 | public function update_data() 48 | { 49 | return [ 50 | // Add permission 51 | ['permission.add', ['a_phpbb_ads_m', true]], 52 | ['permission.add', ['a_phpbb_ads_s', true]], 53 | 54 | // Set permissions 55 | ['if', [ 56 | ['permission.role_exists', ['ROLE_ADMIN_FULL']], 57 | ['permission.permission_set', ['ROLE_ADMIN_FULL', 'a_phpbb_ads_m']], 58 | ]], 59 | ['if', [ 60 | ['permission.role_exists', ['ROLE_ADMIN_FULL']], 61 | ['permission.permission_set', ['ROLE_ADMIN_FULL', 'a_phpbb_ads_s']], 62 | ]], 63 | ['if', [ 64 | ['permission.role_exists', ['ROLE_ADMIN_STANDARD']], 65 | ['permission.permission_set', ['ROLE_ADMIN_STANDARD', 'a_phpbb_ads_m']], 66 | ]], 67 | ['if', [ 68 | ['permission.role_exists', ['ROLE_ADMIN_STANDARD']], 69 | ['permission.permission_set', ['ROLE_ADMIN_STANDARD', 'a_phpbb_ads_s']], 70 | ]], 71 | 72 | // Update module auth 73 | ['custom', [[$this, 'update_acp_module_auth']]], 74 | ]; 75 | } 76 | 77 | /** 78 | * Update module auth manually, because "module.remove" tool causes problems when deleting extension. 79 | */ 80 | public function update_acp_module_auth() 81 | { 82 | $sql = 'UPDATE ' . $this->container->getParameter('tables.modules') . " 83 | SET module_auth = 'ext_phpbb/ads && acl_a_phpbb_ads_m' 84 | WHERE module_langname = 'ACP_MANAGE_ADS_TITLE'"; 85 | $this->db->sql_query($sql); 86 | 87 | $sql = 'UPDATE ' . $this->container->getParameter('tables.modules') . " 88 | SET module_auth = 'ext_phpbb/ads && acl_a_phpbb_ads_s' 89 | WHERE module_langname = 'ACP_ADS_SETTINGS_TITLE'"; 90 | $this->db->sql_query($sql); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpbb-ads", 3 | "author": "phpBB Limited", 4 | "license": "GPL-2.0", 5 | "scripts": { 6 | "copy-adblock": "copyfiles --flat node_modules/just-detect-adblock/dist/bundle.umd.js styles/all/template/js" 7 | }, 8 | "dependencies": { 9 | "just-detect-adblock": "^1.1.0" 10 | }, 11 | "devDependencies": { 12 | "copyfiles": "^2.4.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /styles/all/template/event/memberlist_view_content_append.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_AFTER_PROFILE, AD_AFTER_PROFILE_ID, AD_AFTER_PROFILE_CENTER) }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/memberlist_view_content_prepend.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_BEFORE_PROFILE, AD_BEFORE_PROFILE_ID,AD_BEFORE_PROFILE_CENTER) }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/overall_footer_after.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_BELOW_FOOTER, AD_BELOW_FOOTER_ID, AD_BELOW_FOOTER_CENTER) }} 4 | {# end ad location #} 5 | 6 | {% include '@phpbb_ads/includes/ad_views.html' %} 7 | 8 | {% if S_DISPLAY_ADBLOCKER %} 9 | {% INCLUDEJS '@phpbb_ads/js/bundle.umd.js' %} 10 | {% endif %} 11 | -------------------------------------------------------------------------------- /styles/all/template/event/overall_footer_body_after.html: -------------------------------------------------------------------------------- 1 | {% if AD_POP_UP and AD_POP_UP_ID %} 2 | {% include '@phpbb_ads/includes/phpbb_ads_pop_up.html' %} 3 | {% endif %} 4 | 5 | {% if AD_SLIDE_UP and AD_SLIDE_UP_ID %} 6 | {% include '@phpbb_ads/includes/phpbb_ads_slide_up.html' %} 7 | {% endif %} 8 | 9 | {% if S_PHPBB_ADS_VISUAL_DEMO %} 10 | 19 | {% endif %} 20 | 21 | {% if S_DISPLAY_ADBLOCKER %} 22 | 30 | {% endif %} 31 | -------------------------------------------------------------------------------- /styles/all/template/event/overall_footer_copyright_prepend.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_AFTER_FOOTER_NAVBAR, AD_AFTER_FOOTER_NAVBAR_ID, AD_AFTER_FOOTER_NAVBAR_CENTER) }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/overall_footer_page_body_after.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {# clear: both; is introduced because of jumpbox in user profile which is floating right #} 3 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 4 | {{ ad.renderAds(AD_ABOVE_FOOTER, AD_ABOVE_FOOTER_ID, AD_ABOVE_FOOTER_CENTER, 'clear: both;') }} 5 | {# end ad location #} 6 | -------------------------------------------------------------------------------- /styles/all/template/event/overall_header_body_before.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_ABOVE_HEADER, AD_ABOVE_HEADER_ID, AD_ABOVE_HEADER_CENTER, 'margin: 0 0 10px 0;') }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/overall_header_content_before.html: -------------------------------------------------------------------------------- 1 | {% INCLUDECSS '@phpbb_ads/phpbbads.css' %} 2 | {% include '@phpbb_ads/includes/ad_clicks.html' %} 3 | {% include '@phpbb_ads/includes/ad_blocker.html' %} 4 | {% include '@phpbb_ads/includes/ad_visual_demo_notice.html' %} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/overall_header_navbar_before.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_BELOW_HEADER, AD_BELOW_HEADER_ID, AD_BELOW_HEADER_CENTER) }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/overall_header_page_body_before.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_AFTER_HEADER_NAVBAR, AD_AFTER_HEADER_NAVBAR_ID, AD_AFTER_HEADER_NAVBAR_CENTER) }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/overall_header_stylesheets_after.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {{ AD_SCRIPTS }} 3 | {# end ad location #} 4 | -------------------------------------------------------------------------------- /styles/all/template/event/quickreply_editor_panel_after.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_AFTER_QUICKREPLY, AD_AFTER_QUICKREPLY_ID, AD_AFTER_QUICKREPLY_CENTER) }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/quickreply_editor_panel_before.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_BEFORE_QUICKREPLY, AD_BEFORE_QUICKREPLY_ID, AD_BEFORE_QUICKREPLY_CENTER) }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/viewtopic_body_poll_after.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_BEFORE_POSTS, AD_BEFORE_POSTS_ID, AD_BEFORE_POSTS_CENTER) }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/event/viewtopic_body_postrow_post_after.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% if loops.postrow|length > 1 and postrow.S_FIRST_ROW %} 3 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 4 | {{ ad.renderAds(AD_AFTER_FIRST_POST, AD_AFTER_FIRST_POST_ID, AD_AFTER_FIRST_POST_CENTER) }} 5 | {% endif %} 6 | {# end ad location #} 7 | 8 | {# begin ad location #} 9 | {% if not postrow.S_FIRST_ROW %} 10 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 11 | {{ ad.renderAds(AD_AFTER_NOT_FIRST_POST, AD_AFTER_NOT_FIRST_POST_ID, AD_AFTER_NOT_FIRST_POST_CENTER) }} 12 | {% endif %} 13 | {# end ad location #} 14 | -------------------------------------------------------------------------------- /styles/all/template/event/viewtopic_body_topic_actions_before.html: -------------------------------------------------------------------------------- 1 | {# begin ad location #} 2 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 3 | {{ ad.renderAds(AD_AFTER_POSTS, AD_AFTER_POSTS_ID, AD_AFTER_POSTS_CENTER) }} 4 | {# end ad location #} 5 | -------------------------------------------------------------------------------- /styles/all/template/includes/ad_blocker.html: -------------------------------------------------------------------------------- 1 | {% if S_DISPLAY_ADBLOCKER %} 2 | 7 | {% endif %} 8 | -------------------------------------------------------------------------------- /styles/all/template/includes/ad_clicks.html: -------------------------------------------------------------------------------- 1 | {% if S_PHPBB_ADS_ENABLE_CLICKS %} 2 | 5 | {% INCLUDEJS '@phpbb_ads/js/clicks.js' %} 6 | {% endif %} 7 | -------------------------------------------------------------------------------- /styles/all/template/includes/ad_views.html: -------------------------------------------------------------------------------- 1 | {% if S_INCREMENT_VIEWS %} 2 | 11 | {% endif %} 12 | -------------------------------------------------------------------------------- /styles/all/template/includes/ad_visual_demo_notice.html: -------------------------------------------------------------------------------- 1 | {% if S_PHPBB_ADS_VISUAL_DEMO %} 2 |
3 |
4 | {{ lang('VISUAL_DEMO') ~ lang('COLON') }} {{ lang('DISABLE_VISUAL_DEMO') }} 5 |
6 |
7 | {% endif %} 8 | -------------------------------------------------------------------------------- /styles/all/template/includes/phpbb_ads_pop_up.html: -------------------------------------------------------------------------------- 1 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 2 | 12 | -------------------------------------------------------------------------------- /styles/all/template/includes/phpbb_ads_slide_up.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {% import '@phpbb_ads/phpbb_ads_macro.html' as ad %} 4 | {{ ad.renderAds(AD_SLIDE_UP, AD_SLIDE_UP_ID, AD_SLIDE_UP_CENTER, 'margin: 0;') }} 5 |
6 | 7 | 29 | -------------------------------------------------------------------------------- /styles/all/template/js/bundle.umd.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).justDetectAdblock=e()}(this,(function(){"use strict";function t(){return void 0!==navigator.brave&&void 0!==navigator.brave.isBrave}function e(){return"string"==typeof navigator.userAgent&&navigator.userAgent.match(/Opera|OPR\//)}function n(){return new Promise((function(t,e){var n=new XMLHttpRequest;n.onreadystatechange=function(){4==n.readyState&&t(n)},n.open("GET","https://raw.githubusercontent.com/wmcmurray/just-detect-adblock/master/baits/pagead2.googlesyndication.com",!0),n.send()}))}function o(t){return 200===t.status&&!t.responseText.match(/^thistextshouldbethere(\n|)$/)}function i(t){return 0===t.status&&!t.responseText.match(/^thistextshouldbethere(\n|)$/)}function r(){if(null!==window.document.body.getAttribute("abp"))return!0;var t=function(){var t=document.createElement("div");return t.setAttribute("class","pub_300x250 pub_300x250m pub_728x90 text-ad textAd text_ad text_ads text-ads text-ad-links ad-text adSense adBlock adContent adBanner"),t.setAttribute("style","width: 1px !important; height: 1px !important; position: absolute !important; left: -10000px !important; top: -1000px !important;"),t}();window.document.body.appendChild(t);var e=function(t){if(null===t.offsetParent||0==t.offsetHeight||0==t.offsetLeft||0==t.offsetTop||0==t.offsetWidth||0==t.clientHeight||0==t.clientWidth)return!0;if(void 0!==window.getComputedStyle){var e=window.getComputedStyle(t,null);if(e&&("none"==e.getPropertyValue("display")||"hidden"==e.getPropertyValue("visibility")))return!0}return!1}(t);return window.document.body.removeChild(t),e}var u;return{detectAnyAdblocker:function(){return new Promise((function(u,d){if(r())return u(!0);t()||e()?n().then((function(n){return t()?u(o(n)):e()?u(i(n)):void u(!1)})):u(!1)}))},detectDomAdblocker:(u=r,function(){var t=arguments;return new Promise((function(e,n){e(u.apply(this,t))}))}),detectBraveShields:function(){return new Promise((function(e,i){t()?n().then((function(t){e(o(t))})):e(!1)}))},detectOperaAdblocker:function(){return new Promise((function(t,o){e()?n().then((function(e){t(i(e))})):t(!1)}))},isDetected:function(t,e){return function(){return console.warn("just-detect-adblock : "+(e||"This method is deprecated.")),t.apply(this,arguments)}}(r,"The `isDetected()` method is now deprecated, please use `detectAnyAdblocker()` instead, which returns a Promise and can detect more stuff (like Brave Shields).")}})); 2 | -------------------------------------------------------------------------------- /styles/all/template/js/clicks.js: -------------------------------------------------------------------------------- 1 | (function($, u_phpbb_ads_click) { 2 | 'use strict'; 3 | 4 | $(function() { 5 | $('[data-phpbb-ads-id]').on('click', 'a', function(e) { 6 | $.get(u_phpbb_ads_click.replace(/(?:0\?sid=.+|0)$/, $(e.delegateTarget).attr('data-phpbb-ads-id'))); 7 | }); 8 | }); 9 | })(jQuery, u_phpbb_ads_click); 10 | -------------------------------------------------------------------------------- /styles/all/template/phpbb_ads_macro.html: -------------------------------------------------------------------------------- 1 | {% macro renderAds(PHPBB_ADS_CODE, PHPBB_ADS_ID, S_PHPBB_ADS_CENTER = false, PHPBB_ADS_STYLE = '') %} 2 | {% if PHPBB_ADS_CODE %} 3 |
4 | {{ PHPBB_ADS_CODE }} 5 |
6 | {% endif %} 7 | {% endmacro %} 8 | -------------------------------------------------------------------------------- /styles/all/theme/phpbbads.css: -------------------------------------------------------------------------------- 1 | .phpbb-ads { 2 | margin: 10px 0; 3 | } 4 | 5 | .phpbb-ads-center { 6 | text-align: center; 7 | } 8 | 9 | .phpbb-ads-center > :first-child:not(script) { 10 | display: inline-block; 11 | max-width: 100%; 12 | } 13 | 14 | .phpbbad-slide-up { 15 | position: fixed; 16 | bottom: 0; 17 | width: 100%; 18 | transition: transform 0.3s; 19 | transform: translateY(100%); 20 | } 21 | 22 | .phpbbad-slide-up-center { 23 | text-align: center; 24 | } 25 | 26 | .phpbbad-slide-up-close { 27 | background-color: #ffffff; 28 | width: 30px; 29 | cursor: pointer; 30 | } 31 | 32 | .phpbb-ads-visual-demo { 33 | font-size: 12px; 34 | font-weight: bold; 35 | line-height: 44px; 36 | text-align: center; 37 | background-color: #f0e68c; 38 | border: #ff0000 dashed 3px; 39 | color: #bc2a4d; 40 | box-sizing: border-box; 41 | width: 100%; 42 | height: 50px; 43 | } 44 | 45 | .phpbb-ads-visual-demo-btn { 46 | text-align: center; 47 | width: 25%; 48 | margin: 0 auto !important; 49 | padding: 10px !important; 50 | } 51 | 52 | .phpbb-ads-button { 53 | font-family: system-ui, sans-serif; 54 | font-size: 13px; 55 | vertical-align: middle; 56 | background: #e3e3e3; 57 | background: linear-gradient(to bottom, #e3e3e3 0%, #f7f7f7 100%); 58 | border: solid 1px #afafaf; 59 | box-shadow: inset 1px 1px 2px #ffffff; 60 | margin: 2px 0; 61 | padding: 3px 8px; 62 | } 63 | 64 | .phpbb-ads-button:link { 65 | color: #000000; 66 | } 67 | 68 | .phpbb-ads-button:link:hover { 69 | text-decoration: none; 70 | } 71 | 72 | .phpbb-ads-button:hover { 73 | border-color: #bc2a4d; 74 | color: #bc2a4d; 75 | cursor: pointer; 76 | } 77 | 78 | .phpbb-ads-button:active { 79 | background: #c3c3c3; 80 | } 81 | -------------------------------------------------------------------------------- /styles/prosilver/template/ucp_ads_stats.html: -------------------------------------------------------------------------------- 1 | {% include 'ucp_header.html' %} 2 | 3 |

{{ lang('UCP_PHPBB_ADS_STATS') }}

4 |
5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | {% if S_VIEWS_ENABLED %}{% endif %} 13 | {% if S_CLICKS_ENABLED %}{% endif %} 14 | 15 | 16 | 17 | 18 | {% set NOW = "now"|date("U") %} 19 | {% for list in [ 20 | { 21 | 'heading': lang('ACTIVE_ADS'), 22 | 'loop': loops.ads 23 | }, 24 | { 25 | 'heading': lang('EXPIRED_ADS'), 26 | 'loop': loops.expired 27 | } 28 | ] %} 29 | {% if list.loop %} 30 | 31 | {% for ad in list.loop %} 32 | 33 | 34 | 35 | 40 | {% if S_VIEWS_ENABLED %} 41 | 46 | {% endif %} 47 | {% if S_CLICKS_ENABLED %} 48 | 53 | {% endif %} 54 | 61 | 62 | {% endfor %} 63 | {% elseif not loops.ads and not loops.expired and loop.last %} 64 | 65 | 66 | 67 | {% endif %} 68 | {% endfor %} 69 | 70 |
{{ lang('AD_NAME') }}{{ lang('AD_START_DATE') }}{{ lang('AD_END_DATE') }}{{ lang('AD_VIEWS') }}{{ lang('AD_CLICKS') }}{{ lang('AD_STATUS') }}
{{ list.heading }}
{{ ad.NAME }}{{ ad.START_DATE ? ad.START_DATE|date(constant('\\phpbb\\ads\\ext::DATE_FORMAT')) }} 36 | {% if ad.END_DATE < NOW %}{% endif %} 37 | {{ ad.END_DATE ? ad.END_DATE|date(constant('\\phpbb\\ads\\ext::DATE_FORMAT')) }} 38 | {% if ad.END_DATE < NOW %}{% endif %} 39 | 42 | {% if ad.VIEWS_LIMIT and ad.VIEWS >= ad.VIEWS_LIMIT %}{% endif %} 43 | {{ ad.VIEWS }}{% if ad.VIEWS_LIMIT %} / {{ ad.VIEWS_LIMIT }}{% endif %} 44 | {% if ad.VIEWS_LIMIT and ad.VIEWS >= ad.VIEWS_LIMIT %}{% endif %} 45 | 49 | {% if ad.CLICKS_LIMIT and ad.CLICKS >= ad.CLICKS_LIMIT %}{% endif %} 50 | {{ ad.CLICKS }}{% if ad.CLICKS_LIMIT %} / {{ ad.CLICKS_LIMIT }}{% endif %} 51 | {% if ad.CLICKS_LIMIT and ad.CLICKS >= ad.CLICKS_LIMIT %}{% endif %} 52 | 55 | {% if list.loop == loops.expired %} 56 | {{ lang('EXPIRED') }} 57 | {% else %} 58 | {% if ad.S_ENABLED %}{{ lang('ENABLED') }}{% else %}{{ lang('DISABLED') }}{% endif %} 59 | {% endif %} 60 |
{{ lang('NO_ADS') }}
71 |
72 |
73 | 74 | {% include 'ucp_footer.html' %} 75 | -------------------------------------------------------------------------------- /styles/scaffoldBB/template/ucp_ads_stats.html: -------------------------------------------------------------------------------- 1 | {% include 'ucp_header.html' %} 2 | 3 |

{{ lang('UCP_PHPBB_ADS_STATS') }}

4 |
5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | {% if S_VIEWS_ENABLED %}{% endif %} 13 | {% if S_CLICKS_ENABLED %}{% endif %} 14 | 15 | 16 | 17 | 18 | {% set NOW = "now"|date("U") %} 19 | {% for list in [ 20 | { 21 | 'heading': lang('ACTIVE_ADS'), 22 | 'loop': loops.ads 23 | }, 24 | { 25 | 'heading': lang('EXPIRED_ADS'), 26 | 'loop': loops.expired 27 | } 28 | ] %} 29 | {% if list.loop %} 30 | 31 | {% for ad in list.loop %} 32 | 33 | 34 | 35 | 40 | {% if S_VIEWS_ENABLED %} 41 | 46 | {% endif %} 47 | {% if S_CLICKS_ENABLED %} 48 | 53 | {% endif %} 54 | 61 | 62 | {% endfor %} 63 | {% elseif not loops.ads and not loops.expired and loop.last %} 64 | 65 | 66 | 67 | {% endif %} 68 | {% endfor %} 69 | 70 |
{{ lang('AD_NAME') }}{{ lang('AD_START_DATE') }}{{ lang('AD_END_DATE') }}{{ lang('AD_VIEWS') }}{{ lang('AD_CLICKS') }}{{ lang('AD_STATUS') }}
{{ list.heading }}
{{ ad.NAME }}{{ ad.START_DATE ? ad.START_DATE|date(constant('\\phpbb\\ads\\ext::DATE_FORMAT')) }} 36 | {% if ad.END_DATE < NOW %}{% endif %} 37 | {{ ad.END_DATE ? ad.END_DATE|date(constant('\\phpbb\\ads\\ext::DATE_FORMAT')) }} 38 | {% if ad.END_DATE < NOW %}{% endif %} 39 | 42 | {% if ad.VIEWS_LIMIT and ad.VIEWS >= ad.VIEWS_LIMIT %}{% endif %} 43 | {{ ad.VIEWS }}{% if ad.VIEWS_LIMIT %} / {{ ad.VIEWS_LIMIT }}{% endif %} 44 | {% if ad.VIEWS_LIMIT and ad.VIEWS >= ad.VIEWS_LIMIT %}{% endif %} 45 | 49 | {% if ad.CLICKS_LIMIT and ad.CLICKS >= ad.CLICKS_LIMIT %}{% endif %} 50 | {{ ad.CLICKS }}{% if ad.CLICKS_LIMIT %} / {{ ad.CLICKS_LIMIT }}{% endif %} 51 | {% if ad.CLICKS_LIMIT and ad.CLICKS >= ad.CLICKS_LIMIT %}{% endif %} 52 | 55 | {% if list.loop == loops.expired %} 56 | {{ lang('EXPIRED') }} 57 | {% else %} 58 | {% if ad.S_ENABLED %}{{ lang('ENABLED') }}{% else %}{{ lang('DISABLED') }}{% endif %} 59 | {% endif %} 60 |
{{ lang('NO_ADS') }}
71 |
72 |
73 | 74 | {% include 'ucp_footer.html' %} 75 | -------------------------------------------------------------------------------- /ucp/main_info.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\ucp; 12 | 13 | /** 14 | * Advertisement management UCP module info. 15 | */ 16 | class main_info 17 | { 18 | public function module() 19 | { 20 | return array( 21 | 'filename' => '\phpbb\ads\ucp\main_module', 22 | 'title' => 'UCP_PHPBB_ADS_TITLE', 23 | 'modes' => array( 24 | 'stats' => array( 25 | 'title' => 'UCP_PHPBB_ADS_STATS', 26 | 'auth' => 'ext_phpbb/ads && acl_u_phpbb_ads', 27 | 'cat' => array('UCP_PHPBB_ADS_TITLE') 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ucp/main_module.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace phpbb\ads\ucp; 12 | 13 | /** 14 | * Advertisement management ACP module. 15 | */ 16 | class main_module 17 | { 18 | public $page_title; 19 | public $tpl_name; 20 | public $u_action; 21 | 22 | /** 23 | * Main UCP module 24 | * 25 | * @throws \Exception 26 | */ 27 | public function main() 28 | { 29 | global $phpbb_container; 30 | 31 | /** @var \phpbb\ads\controller\ucp_controller $ucp_controller */ 32 | $ucp_controller = $phpbb_container->get('phpbb.ads.ucp.controller'); 33 | 34 | // Make the $u_action url available in the UCP controller 35 | $ucp_controller->set_page_url($this->u_action); 36 | 37 | // Load a template 38 | $this->tpl_name = 'ucp_ads_stats'; 39 | 40 | // Set the page title for our UCP page 41 | $this->page_title = 'UCP_PHPBB_ADS_STATS'; 42 | 43 | $ucp_controller->main(); 44 | } 45 | } 46 | --------------------------------------------------------------------------------