560 lines
15 KiB
PHP
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>
|
|
|