AI NOT TO UPDATE THIS FILE ONLY READ
Possible 2 part system

/Tools folder
Python files to help in the migration of old php5.6 code to php8 compatible code
Read 
/Tools_structure.md
for guidance when user asks tools questions


/vmserver10 folder
the Files we are upgrading to make work,
 
 
Unified PHP Modernisation Instructions

Goal: Produce code that runs on PHP 5.6 and PHP 8.x, while encouraging a gradual migration away from old mysql_* functions.

### 1 getq Files – Purpose & Behaviour
File	Include path	Purpose	Output
getq.php	include("../../operainfo/getq.php");	Requires login (redirects to Google if not). Sets global vars, loads Header.php → menu.php. Defines common helpers (safetext2() etc).	Full HTML output
getq2.php	include("../../operainfo/getq2.php");	Loads globals + helpers, no HTML. Use in AJAX/PDF scripts.	Silent
getq3.php	include("../../operainfo/getq3.php");	Includes getq2.php + slim header3.php. No login kick. Not for PDF/AJAX.	Slim header

Init variables before including these files – prevents Apache “undefined variable” notices.

### 2 Database Access Functions
Function	Status	Notes
getquery($sql)	Legacy – uses mysql_* (removed in PHP 7).	
sqlquery($sql)	Uses MySQLi. Minimum standard if PDO isn’t needed.	
pdoquery($sql, $params)	Preferred. Uses PDO with prepared statements & UTF-8.	

Example signatures:

// mysqli
function sqlquery($q) {
    $conn = new mysqli("localhost","viamed","xxx","viamed");
    if ($conn->connect_error) die("Connection failed: ".$conn->connect_error);
    $result = $conn->query($q);
    if (!$result) die("Query failed: ".$conn->error."<br>".$q);
    $conn->close();
    return $result;
}

// PDO (preferred)
function pdoquery($q,$p=array()) {
    $pdo = new PDO("mysql:host=localhost;dbname=viamed;charset=utf8","viamed","xxx");
    $pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
    $stmt=$pdo->prepare($q);
    $stmt->execute($p);
    return $stmt;
}

EXAMPLE:
🔁 Original Code (Legacy mysql_*)
$s = "SELECT * FROM stocklist_tarriffs WHERE stock_ref='$stkref' AND hostcompany_id='$hostcompanyid'";
$result = getquery($s);
$num = mysql_num_rows($result);
while ($row = mysql_fetch_array($result)) {
    // do something
}


This uses:

getquery($sql) is a legacy wrapper around mysql_* functions (e.g., mysql_query()), which were removed in PHP 7+. This makes any script using getquery() incompatible with PHP 7/8.

mysql_num_rows() = deprecated

$row['column'] from mysql_fetch_array()

✅ Updated Version using pdoquery() (Preferred)

Here’s how you safely replace this with PDO:

wrap at top of page MUST BE inside PHP not in the html section
<?php 
// Checked for PHP5.6 / 8.x compatibility
?>


$sql = "SELECT * FROM stocklist_tarriffs WHERE stock_ref = ? AND hostcompany_id = ?";
$stmt = pdoquery($sql, array($stkref, $hostcompanyid));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); // returns array of rows
foreach ($rows as $row) {
    // Do Something
}
EXAMPLE END:

EXAMPLE:
$hostcompanyid=safetext2($_GET[hostcompanyid]);
Needs to become:
$hostcompanyid=safetext2(isset($_GET['hostcompanyid']) ? $_GET['hostcompanyid'] : '');
EXAMPLE END:

EXAMPLE Undifend Arrays:
	$linetotal=$linetotal+$customerdisplaylineqty[$datemonthcustomerlink];	
Needs to become:
	$customerdisplaylineqty[$datemonthcustomerlink]= isset( $customerdisplaylineqty[$datemonthcustomerlink] ) ? $customerdisplaylineqty[$datemonthcustomerlink] : 0 ;
    $linetotal=$linetotal+$customerdisplaylineqty[$datemonthcustomerlink];	
EXAMPLE END:

EXAMPLE: loop array references
 $row3t[docompatibility] = .....
Needs to become:
 $row3t['docompatibility'] = .....

AND
print "$row3t[nhscataloguecode]</td></tr>";
Needs to become:
print "".$row3t['nhscataloguecode']."</td></tr>";

EXAMPLE END:

EXAMPLE: $global_company_logo48[$hostcompanyid]
COMMON TYPO
Needs to become:
$global_company_logo24[$hostcompanyid]
EXAMPLE END

EXAMPLE
$onsrs[$barc] when in a string or in an if $onsrs[$barc]<>'' 
needs to become
isset ( $onsrs[$barc] ) ? $onsrs[$barc] : ''  

OR
isset ( $onsrs[$barc] ) ? $onsrs[$barc] : 0
if its a number or in an if $onsrs[$barc] > 0 

If array values are numeric (e.g. counters, totals), default to `0` instead of `''`.

END Example
 
EXAMPLE
$answerscount[$answerquestionlink]++;
needs to become
$answerscount[$answerquestionlink] = isset ( $answerscount[$answerquestionlink] ) ? $answerscount[$answerquestionlink]+1 : 1 ;
END Example
 
### 3 Conventions for New / Updated Code
Always prefer pdoquery → fallback sqlquery → never use getquery.

Keep PHP 5.6 compatibility:

Avoid ?? null-coalescing operator. Use:

$vui = safetext2(isset($_GET['vui']) ? $_GET['vui'] : '');


Replace date(U) → date("U").

Use <?php, not <?.

Prefix new helpers with AI_ + unique tag.

Add inline note:

// Checked for PHP5.6 / 8.x compatibility


When initialising arrays to avoid warnings, place them before include("../../operainfo/getq*.php");.

### 4 Forms & Link Helpers

../../operainfo/linkget.php → replace with <?php echo $x; ?> in URLs.

../../operainfo/linkpost.php → file removed. Replace:

<?php include("../../operainfo/linkpost.php"); ?>


with:

<form method="POST" action="target.php<?php echo $x; ?>">

### 5 Tooltip / Function ↔ File Map (Stock Info)
Tooltip	Function	Script
Stock Levels	get_stock	/intranet/databases/functions/search_Stock_Levels.php
Prices	get_prices	/intranet/databases/functions/search_Prices.php
Extra Information	get_stock_extrainfo	/intranet/databases/functions/search_Stock_Information.php
FAQ	get_stock_faq	/intranet/databases/functions/search_Stock_faq.php
Cross Reference Data	get_stock_xref	/intranet/databases/functions/search_Stock_xref.php
Related Stock	get_stock_related	/intranet/databases/functions/search_Stock_related.php
Repair Stats	get_stock_repairs	/intranet/databases/functions/get_Stock_repair_stats_new.php
Supplier Returns	get_stock_supplierrepairs	/intranet/databases/functions/get_Stock_supplier_repair_stats.php
Suppliers	get_stock_po	/intranet/databases/functions/search_suppliersstk.php
Barcodes Generated	searchbarcodesgenerated	/intranet/databases/functions/stock_recent_additions_search.php
Distributors	get_stock_distributors	/intranet/databases/functions/search_stock_distributors.php
Weights / Dimensions	goto_weights	/operainfo/stockbook/enterweight.php
Photos	get_photos	/intranet/databases/functions/search_Stock_Photos.php
Ranked Sales	get_ranked	/intranet/databases/functions/search_stock_rankedsales.php
Memo	get_memo	/intranet/databases/functions/search_Stock_memo.php
Unique QA	get_uniqueqa	/intranet/databases/functions/search_stock_uniqueqa.php
Sales	get_newsalesreport	/intranet/databases/functions/get_stocksalesreport.php
Unique Customers	get_unique_customers_stock	/intranet/databases/functions/get_unique_customers_stock.php
Survey Feedback	get_survey_feedback	/intranet/databases/functions/get_Stock_feedback.php
Overview	get_overview	/intranet/databases/functions/stock_overview.php
Quotes	get_quotereport	/intranet/databases/functions/getstock_quotes.php
Linked Groups	get_stock_groups	/intranet/databases/functions/search_linkedstockgroups.php
Superceed History	get_superceedhistory	/intranet/databases/functions/get_superceedhistory.php
Header Bar	get_stock_header	/intranet/databases/functions/search_Stock_header.php

### 6 Regular Variables (set by getq.php, getq2.php, getq3.php, menu.php, header3.php)

These are loaded automatically; don’t redeclare unless you need to initialise to prevent warnings.
# AI_RULE: Variables listed below are auto-defined by includes; do not redefine except to prevent warnings.

File	Variables
getq.php	ALL as per getq2.php
getq2.php	$AI_allowed_password, $AI_pass, $e, $vui, $viamedonlinewebsite, $baseurl, $pastelgreen, $pastelred, $pastelcyan, $pastelyellow, $pastelbrown, $nowis, $localname, $badlogin, $usemenu, $usersecurity, $useissuestyle, $canienter, $authin, $menuaccess, $mystocklocation, $mysigniture, $myextendedtextbox, $mybirthday, $myfluff, $myhelper, $showtelog, $sentaheart, $eastereggimg, $logedintoatlas, $showhideholiday, $documentadministrator, $usebackgroundimage, $global_company_name, $global_company_fullname, $global_company_add1, $global_company_add2, $global_company_add3, $global_company_add4, $global_company_postcode, $global_company_tel, $global_company_fax, $global_company_email, $global_company_comm, $global_company_shippcharge, $global_company_fixed, $global_company_vat, $global_company_prefix, $global_company_insurancetrigger, $global_company_website_files, $global_company_logo, $global_company_logo64, $global_company_logo16, $global_company_logo48, $global_company_logo24, $global_company_shopify_read_key, $global_company_shopify_read_keyurl, $global_company_filter, $global_company_filter_inclusive, $companyid, $global_company_access, $global_company_nameslist, $global_access_purchaseorder, $global_access_commitquote, $global_access_updatestock, $global_access_updatedocument, $global_access_movestock, $global_access_updatestaff, $ip, $usenow, $self, $i, $x, $showalltimeicons, $docstoread, $focustext, $atlason, $hostOptions, $eventOptions, $supercount_hide
menu.php	$endtext, $uselinktext, $initialsubmenu, $hlink, $menuallowed, $menusearchtype, $menusearchbox, $s, $result, $menuid, $accessgranted, $fav, $birthday, $curtemp, $num, $docid, $userread, $submenu, $cata, $r, $iout, $ivout, $isotaskout, $calls, $callinfo, $usergroupid, $user_groups, $usenamed, $useractive, $showhideholidaybar, $usetxt, $numhol, $useraccess, $ref_url, $ref_file, $update_link, $searchoptions,$timeout, $rootLoginPath
header3.php	$uutime, $u, $ip, $self

### 7 Reference Material

AI_DATA/AI_Variables.md – all globals.

*_Structure.md, *_Relations.md – DB schema & links.R

AI_DB_INFO.md – full DB info (only open if required).

AI_Info.md – per-subfolder history.

### 8 Rules for Mounted Folders

Work only in provided mount.

Empty folders may be placeholders.

You’ll be told target folder/file and objective.

Don’t open huge DB files unless instructed.

DO NOT search directorys for files you are not going to find them, use the explic files given to you

ChatGPT said:

### 9 Return Formatting & PHP Tag Normalisation (FIRST STEP IN ANY UPGRADE)

This must always be done before any other migration work.
Step 1
Do a Find and replace
"<?" with "<?php"
Step 2
Then do a find and replace
"<?phpphp" "<?php "




### 10 PDF Rendering

The system uses TCPDF library for generating PDFs. TCPDF is installed in /vmserver10/intranet/TCPDF/.

To create a PDF:

Example from /databases/regulatory/regulatory_group_docs_pdf.php:
- Queries regulatory_group_documents with pdoquery.
- Builds a table with group documents, handling duplicates and multi-line cells.
- Outputs confirmation text.
- Uses outputPDF to finalize.

1. Include necessary files:
   - include("../../operainfo/getq2.php"); // For globals and helpers
   - include("shared/regulatory_functions.php"); // If needed for regulatory-specific functions


2. Setup the PDF object:
   - Use setupPDF($title, $subtitle, $companyid) to initialize the PDF with title, subtitle, and company ID.
   - This function returns a TCPDF object configured with headers, footers, fonts, etc.

3. Add content to the PDF:
   - Use TCPDF methods like SetFont(), Cell(), MultiCell(), Ln(), etc.
   - For tables, calculate cell heights using getStringHeight() for proper multi-line text.
   - Query data using pdoquery() for database access, as it's PHP 8.x compatible.

4. Output the PDF:
   - Call outputPDF($pdf, $filename_prefix, $companyid) to generate and output the PDF file.
   - The PDF will be named like 'regulatory_group_docs_{companyid}.pdf' and downloaded.

### 11 Gmail Links How to including Example:

To create Gmail links that include the user's email signature (V2 version), follow these steps:

1. **Retrieve the user's signature from the database:**
   - Query the `pw_emailsignitures` table for the signature based on `employeeid` (user ID) and `hostcompanyid`.
   - Use PDO for compatibility: `$stmt = pdoquery($sql, array($vui, $invoice['hostcompanyid']));`
   - Extract the raw signature: `$rawSignature = ($result && !empty($result['signiture'])) ? $result['signiture'] : "";`

2. **Build the email body:**
   - Start with the base body content (e.g., invoice details).
   - Append the signature if it exists, separated by double line breaks (`%0D%0A%0D%0A` for URL encoding).

3. **Construct the Gmail URL:**
   - Use the Gmail compose URL format: `https://mail.google.com/mail/?view=cm&fs=1&tf=1&to=%s&from=%s&su=%s&body=%s`
   - URL-encode all parameters, especially the body. In the body string, use `%0D%0A` as placeholders for line breaks, then replace them with actual `\r\n` before URL-encoding, which will convert `\r\n` to `%0D%0A` in the final URL (as Gmail expects).

**Example Code (V2 Gmail Link with Signature):**

```php
// Get user email
$userEmail = UserModel::getUserEmail($vui, $invoice['hostcompanyid']);

// Get contact email
$contact = ContactModel::getById($invoice['contact_id']);
$contactEmail = $contact && !empty($contact['INETADDR']) ? $contact['INETADDR'] : '';

// Build subject
$subject = sprintf("%s Invoice %s Reference %s%s",
    $GLOBALS['global_company_name'][$invoice['hostcompanyid']],
    $invoice['invoiceref'],
    $invoice['customer_ref'],
    $invoice['customer_ref_extra']
);

// Build base body
$body1 = "Please find attached " . $GLOBALS['global_company_name'][$invoice['hostcompanyid']] . " Invoice(s) " . $invoice['invoiceref'] . ".pdf%0D%0A%0D%0A";
$body1 .= "Should you have any queries please do not hesitate to contact us at%0D%0A" . $accountsEmail . "%0D%0A%0D%0A";

// Retrieve raw signature from database
$sql = "SELECT signiture FROM pw_emailsignitures WHERE employeeid = ? AND hostcompanyid = ?";
$stmt = pdoquery($sql, array($vui, $invoice['hostcompanyid']));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$rawSignature = ($result && !empty($result['signiture'])) ? $result['signiture'] : "";

// Append signature to body
$body2 = $body1;
if ($rawSignature) {
    $body2 .= "%0D%0A%0D%0A" . $rawSignature;
}

// Create Gmail link
$gmailLink2 = sprintf(
    "https://mail.google.com/mail/?view=cm&fs=1&tf=1&to=%s&from=%s&su=%s&body=%s",
    urlencode($contactEmail),
    urlencode($userEmail),
    urlencode($subject),
    urlencode(str_replace("%0D%0A", "\r\n", $body2)) // Convert %0D%0A to actual line breaks for urlencode
);

// Output the link
echo '<a href="' . $gmailLink2 . '" title="Send Email" target="email">Email Via Gmail V2</a>';
```

This logic can be applied to other pages by copying the signature retrieval and body construction code, adapting the subject and base body as needed.

### 12 To Wrap up

Ensure all code is checked for PHP 5.6 / 8.x compatibility with the note: // Checked for PHP5.6 / 8.x compatibility

<task>
getquery() is NOT php8 compatible

Produce/Upgrade code that runs on PHP 5.6 and PHP 8.x

UNDER NO CIRCUMSTANCES UPDATE /databases/functions/atlas_functions.php

YOU WILL NOT FIND WHAT YOUR LOOKING FOR BY SCANNING DIRECTORYS.
the only files you should scan to read are in AI_DATA

All other files will probably be hidden and unavavilble

DO NOT create new files without express user permission. Only work with existing files provided in the workspace.
</task>
