neropay/index.php
2025-03-06 14:50:41 -05:00

560 lines
15 KiB
PHP

<?php
/*********************************************
* Description - Neropay payment system
*
* index.php -- The main script responsible for
* everything.
* Author - Vilyaem
* *******************************************/
/*CONSTANTS*/
define("VILXMPPADDR", "YOUR XMPP ADDRESS");
define("XMPPHOST", "YOUR XMPP HOST (something.xyz)");
define("XMPPUSER", "YOUR XMPP USERNAME (vilyaem)");
define("XMPPPASS", "YOUR XMPP PASSWORD");
define("SQLDBPATH", "data/payments.db");
/*GET THE BLOAT*/
require __DIR__ . '/vendor/autoload.php';
require_once('vendor/monero-integrations/monerophp/src/jsonRPCClient.php');
require_once('vendor/monero-integrations/monerophp/src/walletRPC.php');
use MoneroIntegrations\MoneroPhp\walletRPC;
use chillerlan\QRCode\Data\QRMatrix;
use chillerlan\QRCode\Output\QRStringText;
use chillerlan\QRCode\{QRCode, QROptions};
/*
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(E_ALL);
*/
$db = new SQLite3(SQLDBPATH);
$db->enableExceptions(true);
$db->exec("PRAGMA busy_timeout = 60000;"); /*Hold your horses*/
$db->exec("PRAGMA journal_mode=WAL;");
$open = $db->query('CREATE TABLE IF NOT EXISTS "payments" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"ip" TEXT,
"walletname" TEXT,
"item" TEXT,
"dues" TEXT,
"status" TEXT,
"address" TEXT,
"date" TEXT
)');
if($open === false){
echo 'Failed to create database!';
exit;
}
/*wallet address string we use to avoid
redundant open_wallet calls*/
$newwaladdr = NULL;
/*Benchmarking*/
$time = microtime();
$time = explode(' ', $time);
$time = $time[1] + $time[0];
$start = $time;
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Neropay</title>
<meta http-equiv="refresh" content="25">
</head>
<body>
<center>
<h1>Neropay</h1>
<small>A tiny Monero payment system</small></br>
<?php
/*Is this a Wownero transaction?*/
/*Get out*/
if (!isset($_SERVER['REMOTE_ADDR'])) {
exit;
}
if($_SERVER['REQUEST_METHOD'] === 'GET'){
if(!isset($_GET['item'])){
echo '<p>Welcome to Neropay, a tiny payment processsing system for Monero</p>';
exit;
}
if(isset($_GET['wow'])){
$wow = true;
echo '<p style="color:pink;">You are making a Wownero transaction!</p>';
}
else{
$wow = false;
}
/* Globals */
$ip = $_SERVER['REMOTE_ADDR'];
/*Nasty sanitization*/
$item = substr(str_replace([",", "#", "$", "%", "*", "~", "'", "=", "{", "[", "|", "`", "^", "]", "}", ":", ";", "<", ">", "/", "?", "&"], "",htmlspecialchars($_GET['item'])),0,256);
if(isset($_GET['addr'])){
$buyinfo = substr(str_replace([",", "#", "$", "%", "*", "~", "'", "=", "{", "[", "|", "`", "^", "]", "}", ":", ";", "<", ">", "/", "?", "&"], "",htmlspecialchars($_GET['addr'])),0,512);
}
/*Setup XMPP*/
/*
$xmppsettings = new Norgul\Xmpp\Options();
$xmppsettings
->setHost(XMPPHOST)
->setUsername(XMPPUSER)
->setPassword(XMPPPASS);
$xmppclient = new Norgul\Xmpp\XmppClient($xmppsettings);
$xmppclient->connect();
* /
/*Setup Monero or Wownero*/
if(!$wow){
$walletRPC = new walletRPC('127.0.0.1', 18083, false);
}
else{
$walletRPC = new walletRPC('127.0.0.1', 18084, false);
}
/*********************************************
* Description - Error messages to give to consoomers
* Author - Vilyaem
* *******************************************/
function NeropayError($msg){
echo '<p style="color:red;">Error, please report the following to kenyaz [at] vilyaem.xyz via Email or XMPP: ' . $msg . '</p>';
SendXMPP(VILXMPPADDR,$msg);
/*$xmppclient->disconnect();*/
exit;
}
/*********************************************
* Description - Retarded, PHP does scary stuff
* when you least expect it
* Author - Vilyaem
* *******************************************/
function IsBad($val){
if(!isset($val) || $val === false || $val === NULL){
return true;
}
else{
return false;
}
}
/*********************************************
* Description - Send an XMPP message
* Author - Vilyaem
* Date - Jul 21 2024
* *******************************************/
function SendXMPP($user,$msg){
/*
global $xmppsettings,$xmppclient;
$xmppclient->message->send($msg, $user);
*/
/*Just write to a file for the moment,
is XMPP abhorrently slow?*/
$date = date('Y-m-d h:i:s A');
$file = fopen("data/notes.txt","a") or NeropayError("10013");
fwrite($file,"$date: $msg\n");
fclose($file);
}
/*********************************************
* Description - Get property of a list.
* Author - Vilyaem
* *******************************************/
function GetListProp($object,$prop,$file){
$scanitems = file($file,FILE_IGNORE_NEW_LINES);
/*var_dump($object);*/
/*var_dump($file);*/
/*var_dump($prop);*/
foreach($scanitems as $scanitem){
$itemdata = explode(",",$scanitem);
/*var_dump($itemdata);*/
/*var_dump($itemdata[0]);*/
if($itemdata[0] === $object){
return $itemdata[$prop];/*return type*/
}
}
return NULL; /*failed*/
}
/*********************************************
* Description - Find payment
* Used when checking if a payment is already ongoing
* Author - Vilyaem
* *******************************************/
function FindPayment(){
global $db,$item,$ip;
$stm = $db->prepare('SELECT * FROM payments WHERE ip = :ip AND item = :item AND date = :date AND status = :status');
$stm->bindValue(':ip',$ip);
$stm->bindValue(':item',$item);
$stm->bindValue(':date',date('Y-m-d'));
$stm->bindValue(':status',"unpaid");
$res = $stm->execute();
$row = $res->fetchArray(SQLITE3_NUM);
/*Can't find it*/
if(IsBad($row)){
return false;
}
if(IsBad($res)){
return false; /*failed*/
}
else{
return true; /*There is one*/
}
}
/*********************************************
* Description - Ask for payment
* Author - Vilyaem
* *******************************************/
function AskPayment(){
global $db,$item,$ip,$walletRPC,$newwaladdr,$wow;
/*Access the database and and get the dues and wallet name*/
$stm = $db->prepare('SELECT * FROM payments WHERE ip = :ip AND item = :item AND date = :date AND status = :status');
if($stm === false){
NeropayError("Error code 1002");
}
$stm->bindValue(":ip",$ip);
$stm->bindValue(":item",$item);
$stm->bindValue(":date",date('Y-m-d'));
$stm->bindValue(":status","unpaid");
$res = $stm->execute();
if($res === false){
NeropayError("Error code 1003");
}
/*echo var_dump($stm) . "</br>";*/
/*echo var_dump($res) . "</br>";*/
/*echo var_dump($res->numColumns()) . "</br>";*/
/*echo var_dump($res->columnType(0)) . "</br>";*/
if ($res->numColumns() && $res->columnType(0) === SQLITE3_NULL) {
NeropayError("Error code 1004");
}
if($res->reset() === false){
NeropayError("Error code 1005");
}
$row = $res->fetchArray(SQLITE3_NUM);
/*echo var_dump($stm) . "</br>";*/
/*echo var_dump($res) . "</br>";*/
/*echo var_dump($row) . "</br>";*/
if($row === false){
NeropayError("Error code 1006");
}
/*
else{
echo "<p>AskPayment got a valid row!</p>";
}
*/
/*$db = null;*/
if($newwaladdr === NULL){
$wallet = $walletRPC->open_wallet($row[2],'');
$addr = $walletRPC->get_address();
}
else{
$addr = $newwaladdr;
}
$amnt = $row[4];
/*echo "</br></br>" . var_dump($addr) . "</br>";*/
echo '<img src="'.(new QRCode)->render($addr['address']).'" width=25% height=25% alt="QR Code" />';
/*var_dump($wow);*/
if(!$wow){
echo '<p>Please pay ' . $amnt . ' XMR to ' . $addr['address'] . '</p>';
}
else{
echo '<p>Please pay ' . $amnt * 4005 . ' WOW to ' . $addr['address'] . '</p>';
}
}
/*********************************************
* Description - Get an Item given a payment ID
* Author - Vilyaem
* *******************************************/
function GetItemByPayment(){
global $db,$ip,$item;
$stm = $db->prepare('SELECT * FROM payments WHERE ip = ? AND item = ? AND date = ? AND status = ?');
$stm->bindValue(":ip",$ip);
$stm->bindValue(":item",$item);
$stm->bindValue(":date",date('Y-m-d'));
$stm->bindValue(":status","unpaid");
$res = $stm->execute();
if($res === false){
NeropayError("Error code 1007");
}
$row = $res->fetchArray(SQLITE3_NUM);
return $row[2]; /*This should be the item*/
}
/*********************************************
* Description - Create a new concurrent payment
* in the database. This also creates a new wallet
* Author - Vilyaem
* *******************************************/
function NewPayment(){
global $db,$item,$ip,$walletRPC,$newwaladdr;
/*$db = null;*/
/*Create the wallet*/
$namenum=rand();
$name=md5($namenum);
$makewallet = $walletRPC->create_wallet($name, '');
$newwallet = $walletRPC->open_wallet($name,'');
$newaddress = $walletRPC->get_address();
$newwaladdr = $newaddress;
$newprice = GetListProp($item,2,"data/items.txt");
/*If item does not exist, stop!*/
if($newprice === NULL){
NeropayError("Error code 1008");
}
/*$db = new SQLite3(SQLDBPATH);*/
/*Add the payment to the database*/
$stm = $db->prepare('INSERT INTO "payments" ("ip", "walletname",
"item", "dues", "status", "address", "date")
VALUES (:ip, :walletname, :item, :dues, :status, :address, :date)');
if($stm === false){
NeropayError("Error code 1009");
}
$stm->bindValue(':ip', $ip);
$stm->bindValue(':walletname', $name);
$stm->bindValue(':item', $item);
$stm->bindValue(':dues', $newprice);
$stm->bindValue(':status', 'unpaid');
$stm->bindValue(':address', 'NULL');
$stm->bindValue(':date', date('Y-m-d'));
$res = $stm->execute();
if($stm === false || $res === false){
NeropayError("Error code 1010");
}
/*echo "newpayment: $ip,$name,$item";*/
/*Notify Vilyaem that a new payment process has begun*/
SendXMPP(VILXMPPADDR,'!!! A new payment has begun: ' . $ip . ',' . $item . ',' . $name);
/*Return wallet's address*/
return $newaddress;
}
/*********************************************
* Description - Success
* Author - Vilyaem
* *******************************************/
function Success(){
global $ip,$item,$buyinfo;
$date = date("Y-m-d");
$itemtype = GetListProp($item,1,"data/items.txt");
$profit = GetListProp($item,2,"data/items.txt");
/*Notify via XMPP of the success*/
SendXMPP(VILXMPPADDR,'Congratulations! CLIENT: ' . $ip . ' ITEM: ' . $item . ' DATE: ' . $date . ' PROFIT: ' . $profit);
/*If the item is digital, give the user an immediate download*/
if($itemtype === "digital"){ /*digital*/
ob_clean();
flush();
$filename = "files/$item";
$mimetype = mime_content_type($filename);
header("Content-Type: ".$mimetype );
header("Content-Disposition: attachment; filename=\"$item\"");
/*echo readfile($filename); */
readfile($filename);
}
else{ /*physical*/
/*NeropayError("Error code 1009");*/
if(isset($buyinfo)){
SendXMPP(VILXMMRADDR,$buyinfo);
echo "<p>Your shipping/contact information has been sent.</p>";
}
}
/*Congratulate the user*/
echo "<p style=\"color:green\">Congratulations on your purchase of $item!</p>";
}
/*********************************************
* Description - Check if payment is complete
* Author - Vilyaem
* *******************************************/
function CheckPayment(){
global $db,$item,$ip,$walletRPC,$wow;
/*Get payment from database*/
$stm = $db->prepare('SELECT * FROM payments WHERE ip = :ip AND item = :item AND date = :date');
$stm->bindValue(':ip',$ip);
$stm->bindValue(':item',$item);
$stm->bindValue(':date',date('Y-m-d'));
$res = $stm->execute();
if(IsBad($res)){
NeropayError("Error code 1011");
}
$row = $res->fetchArray(SQLITE3_NUM);
if(IsBad($row)){
NeropayError("Error code 1012");
}
/*echo var_dump($row) . "<br>";*/
/*If payment is already done succeed*/
if($row[4] === "finished"){
return true;
}
/*If not, check it*/
/*Open the wallet and see if the payment has been met*/
$mywallet = $walletRPC->open_wallet($row[2]);
$mybalance = $walletRPC->get_balance()['balance'];
/*echo var_dump($mywallet) . "<br>";*/
/*echo var_dump($mybalance) . "<br>";*/
if(($mybalance >= $row[4] && $wow === false) || ($mybalance >= $row[4] * 4005 && $wow === true)){
/*if(true){*/
/*transfer the money TODO this API call's args are confusing*/
/*echo '<p>' . $walletRPC->transfer() . '</p>'*/
/*Mark as finished*/
$stm = $db->prepare("UPDATE payments SET status='finished' WHERE ip = :ip AND item = :item AND date = :date");
$stm->bindValue(':ip',$ip);
$stm->bindValue(':item',$item);
$stm->bindValue(':date',date('Y-m-d'));
$res = $stm->execute();
if($res === false){
NeropayError("Error code 1013");
}
$row = $res->fetchArray(SQLITE3_NUM);
return true;
}
else{ /*Payment has not succeeded, and the balance has not changed.*/
return false;
}
}
/*********************************************
* Description - Main
* Author - Vilyaem
* *******************************************/
function Main(){
/*Check if this payment is already ongoing*/
if(FindPayment() === true){
/*echo "<p>Found the payment!</p>";*/
/*If payment is already ongoing, check if it has been paid,
if so, show success, otherwise ask for payment*/
if(CheckPayment() === true){
/*echo "<p>Check payment succeeded</p>";*/
Success();
}
else{
/*echo "<p>Check payment falied, ask for payment</p>";*/
AskPayment();
}
}
/*If it is not, create it and ask for payment*/
else{
/*echo "<p>Failed to find the payment!</p>";*/
NewPayment();
AskPayment();
}
}
Main();
/*$xmppclient->disconnect();*/
}
?>
<p>
<small>Note: Payments may take a couple minutes to go through.
</br>Report irregularities or problems to kenyaz [at] vilyaem.xyz
</br>The page should refresh automatically, if not, refresh manually</small>
</br><strong>WARNING: Monero might liberate you.</strong>
</p>
<?php
/*Benchmarking*/
$time = microtime();
$time = explode(' ', $time);
$time = $time[1] + $time[0];
$finish = $time;
$total_time = round(($finish - $start), 4);
echo '<em>Page generated in '.$total_time.' seconds.</em>';
?>
</center>
</body>
</html>