PHP Classes

File: docs/Advertising.md

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   docs/Advertising.md   Download  
File: docs/Advertising.md
Role: Example script
Content type: text/markdown
Description: Example script
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 13,193 bytes
 

Contents

Class file image Download

Advertising

BinktermPHP includes a built-in ANSI advertising system that lets sysops promote services, events, and other BBSes directly within their node ? both on the web dashboard and through scheduled echomail posts into active message areas.

The system is designed around the way FTN networks actually work. Ads are authored in classic ANSI art, stored in a central library, and delivered through two complementary channels: a rotating carousel on the dashboard for visitors browsing the web interface, and automated campaign posts that reach users reading echomail across the network. A single ad can appear in both places simultaneously, or be restricted to one channel.

Campaigns give sysops fine-grained control over timing and reach. Each campaign targets one or more echomail areas and fires on a configurable weekly schedule with per-timezone awareness. Weighted ad selection within a campaign means you can favor certain ads over others without manual intervention. Every post ? whether triggered automatically by the scheduler or run manually ? is recorded in a history log, making it easy to audit what was sent, when, and to which areas.

The ad library tracks content hashes so duplicate uploads are flagged before they crowd out your rotation. Existing flat-file ads from the legacy bbs_ads/ directory are migrated into the database automatically on upgrade, so you don't lose content switching from the old system.

Content is managed from Admin ? Ads and Bulletins ? Content Library. Broadcasts are managed from Admin ? Ads and Bulletins ? Broadcast Manager.

Features

  • Upload ANSI ads directly into the ad library
  • Edit ad metadata and ANSI content in the browser
  • Preview ANSI ads in a modal before saving
  • Tag ads with freeform labels such as `general`, `door`, `network`, or `event`
  • Choose which ads are eligible for the dashboard carousel
  • Build auto-posting campaigns with multiple targets
  • Schedule campaigns by day of week, time, and timezone
  • Track post history for manual and automatic posts
  • Quick Setup wizard for common campaign types
  • Dynamic ads driven by an allowlisted command script
  • Click-through URLs on dashboard ads with impression and click tracking
  • Ad analytics dashboard with per-ad CTR, daily activity, and period filtering
  • Campaign expiry with automatic deactivation

Ad Library

Each ad is stored in the database with:

  • title
  • slug
  • description
  • ANSI content (or a content command ? see Dynamic Ads)
  • content hash for duplicate warning
  • enabled/disabled state
  • dashboard eligibility
  • auto-post eligibility
  • tags
  • click-through URL (optional ? see Click-Through URLs)
  • impression and click counts (tracked automatically)

Duplicate uploads are allowed. If the ANSI payload matches an existing ad, the system warns but does not block the upload.

Tags

Ads can be tagged with freeform labels such as general, door, network, or event.

Tags are used for organization in the library and can also be used by ad campaigns to control eligibility.

Campaign tag filtering supports two modes:

  • Include tags - the campaign will only consider ads matching at least one selected include tag
  • Exclude tags - the campaign will skip any ad matching an excluded tag

Tag filters can be combined with explicitly assigned ads:

  • if a campaign has assigned ads and tag filters, the assigned ad list is narrowed by the tag rules
  • if a campaign has no assigned ads but does have tag filters, the campaign can source eligible ads from the library by tag
  • a campaign must have at least one assigned ad or at least one tag filter

Dashboard Ads

The dashboard advertising window pulls from ads marked for dashboard display.

  • Rotation is per PHP session
  • Left and right arrow controls move through eligible ads
  • Keyboard left/right navigation is supported
  • Duplicate ANSI payloads are de-duplicated in the displayed set

If only one eligible ad exists, the dashboard simply shows that ad without carousel controls.

Quick Setup Wizard

The Quick Setup button on the Broadcast Manager page opens a three-step wizard that pre-configures a new campaign based on a common use case:

| Type | Description | Default schedule | |---|---|---| | Weekly BBS Ad | Post a weekly BBS advertisement to one or more echoareas | Weekly (Tuesdays) | | Event Announcement | Time-limited campaign for a specific event | Daily | | Door Game Promotion | Recurring promotion for a door game or tournament | Tue/Fri | | File Echo Update | Weekly summary of new files generated by an external script | Weekly (Fridays) | | League/Network Recruit | Recruitment drive for a league or network | Mon/Wed/Fri | | Sub of the Week | Highlight a featured echomail area each week | Weekly (Mondays) | | Anniversary/Milestone | Countdown to a system milestone | Daily | | Tech Notice | Short-term technical announcement | Every 3 days | | Node of the Month | Monthly spotlight on a network node | Weekly |

The wizard sets sensible defaults for post interval, repeat gap, schedule, and subject template for each type. Step 2 collects the campaign name, posting user, echoarea targets, subject template, and an optional expiry date. Step 3 shows a review before creating the campaign.

The File Echo Update type automatically creates a dynamic ad linked to scripts/report_newfiles.php and the Weather Report type links to scripts/weather_report.php ? no static ANSI file or manual script selection is needed for either.

Campaigns

Campaigns let the sysop post ads automatically into echomail areas.

Each campaign can define:

  • a posting user
  • one or more active schedules
  • one or more active targets
  • one or more assigned ads with weights
  • optional include/exclude tag filters
  • an optional expiry date (`Expires On`) ? when set, the campaign is automatically deactivated after that date on the next scheduler run

Each target contains:

  • echoarea tag
  • domain
  • subject template
  • enabled/disabled state

Each schedule contains:

  • selected days of the week
  • time of day
  • timezone
  • enabled/disabled state

The campaign runner chooses an eligible ad using weighted random selection. Normal eligibility rules still apply, including active state, auto-post eligibility, and any configured date window on the ad.

Dynamic Ads

An ad can generate its body at post time by setting a Content Command instead of (or in addition to) static ANSI content.

At post time the script is run via proc_open. Its standard output becomes the message body. The post is silently skipped and logged if:

  • the script exits with a non-zero exit code, or
  • the script produces no output (empty stdout after trim)

This allows fully dynamic content ? weekly file listings, player scoreboards, system statistics, or anything else a script can generate.

Allowed Scripts

For security, the content command must be one of:

  • Any file placed in the `content_commands/` directory at the project root
  • `scripts/weather_report.php`
  • `scripts/report_newfiles.php`
  • `scripts/generate_ad.php`

The Content Command field in the ad editor is a dropdown populated from these sources. Free-text entry is not permitted.

The system automatically resolves the selected script to an absolute path and invokes it through PHP_BINARY (for .php scripts) without requiring a php prefix in the value. The content_commands/ directory is the recommended place to install custom scripts for your installation.

Arguments

An optional Arguments field accepts space-separated parameters passed to the script at runtime. For example, selecting scripts/report_newfiles.php and entering --since=14d in the arguments field runs:

php /path/to/scripts/report_newfiles.php '--since=14d'

Each argument is individually passed through escapeshellarg() at execution time. Shell metacharacters (;, |, !, &, >, <, ` `,$,\`, (, ), {, }, *, ?, ", ', ~, #) are also rejected at storage time so that injection attempts cannot be saved.

Creating a Dynamic Ad

Via the Content Library: In Admin ? Ads and Bulletins ? Content Library, select a script from the Content Command dropdown and leave the file picker empty. A title is still required. Enable Allow Auto-Post so campaigns can use it.

Via the Quick Setup wizard: The File Echo Update and Weather Report campaign types automatically create a dynamic ad pre-configured with the appropriate script. No manual selection is needed.

Installing a Custom Script

  1. Place the script in the `content_commands/` directory at the project root.
  2. Make it executable (`chmod +x`).
  3. The script will appear in the Content Command dropdown immediately.

Scripts in content_commands/ follow the same contract as any other content command script (see below).

Writing a Content Command Script

The script must:

  1. Write the complete message body to stdout
  2. Exit with code `0` on success
  3. Exit with a non-zero code or produce no output to signal "nothing to post"

Example skeleton (content_commands/my_report.php):

#!/usr/bin/env php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../src/functions.php';

$db = \BinktermPHP\Database::getInstance()->getPdo();
// ... build report ...
if ($report === '') {
    exit(1); // nothing to post
}
echo $report;
exit(0);

What the Content Command Is For

Use Content Command when the ad body should be generated fresh at post time instead of being stored as a fixed ANSI file in the ad library.

Good fits include:

  • recent files reports
  • joke or quote of the day
  • league standings or tournament ladders
  • nightly maintenance bulletins
  • rotating "what changed this week" summaries
  • generated network or system-status notices

Content Command Examples

Weekly New Files Digest

The built-in scripts/report_newfiles.php script queries recent public uploads and hatched files, groups them by file area, and writes a ready-to-post report to stdout.

Typical use:

  • create a dynamic ad titled `Weekly File Echo Update`
  • select `scripts/report_newfiles.php` from the Content Command dropdown
  • enter `--since=7d` in the Arguments field
  • attach that ad to a Friday campaign posting into one or more file announcement echoes

Custom Generated Bulletins

Place any custom script in content_commands/ and it will appear in the dropdown. Scripts can read local database tables, config files, or other prepared data and emit a complete plain-text or ANSI bulletin for echomail.

Recommended Pattern

For recurring generated posts:

  1. Write a script and place it in `content_commands/` (or use a whitelisted script).
  2. Make it output the full message body to stdout.
  3. Return exit code `0` when the script succeeds and has content to post.
  4. Return exit code `1` when there is nothing worth posting.
  5. Create a dynamic ad and select that script from the Content Command dropdown.
  6. Assign the ad to a campaign with the desired schedule and targets.

This keeps scheduling, targeting, and post logging inside the advertising system while your script controls only the generated body text.

Click-Through URLs

Each ad can optionally include a Click-Through URL. When set, a Visit button appears next to the ad on the dashboard. Clicking it opens the URL in a new tab.

Impressions (how many times the ad was shown) and clicks are tracked automatically per user and stored in the database. Both counts are visible in the Content Library ad list and in the Ad Analytics page.

Ad Analytics

Admin ? Analytics ? Ad Analytics (requires a valid license) provides a performance overview of all ads:

  • Period selector ? filter by last 7 days, 30 days, 90 days, or all time
  • Summary cards ? total impressions, total clicks, overall CTR, and active/total ad count
  • Daily activity chart ? impression and click counts per day as a progress-bar chart
  • Per-ad breakdown table ? impressions, clicks, CTR%, relative reach bar, last impression date, and last click date for each ad

Scheduler Integration

Campaigns are processed automatically by scripts/binkp_scheduler.php.

The scheduler checks due schedule slots and attempts posts for each active campaign target. Matching is based on the configured local schedule time with a grace window for slightly late runs.

For manual testing or one-off runs, you can also use:

php scripts/run_ad_campaigns.php
php scripts/run_ad_campaigns.php --campaign-id=3
php scripts/run_ad_campaigns.php --dry-run

Post History

The Broadcast Manager page includes a post history table showing:

  • post time
  • campaign
  • ad
  • target
  • status
  • subject
  • posting user
  • error text when a post fails

Both manual and automatic campaign runs are recorded in the same history log.

Echomail Posting Notes

  • Outbound ad posts strip SAUCE before the message body is posted
  • Subject templates are stored per target
  • Local-only areas are posted locally without uplink distribution