This is my server side code
<?php
ini_set('display_errors',1);
error_reporting(E_ALL);
use Slim\Http\Request;
use Slim\Http\Response;
use Stripe\Stripe;
require 'vendor/autoload.php';
$dotenv = Dotenv\Dotenv::create(__DIR__);
$dotenv->load();
require './config.php';
$app = new \Slim\App;
$app->add(function ($request, $response, $next) {
Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));
return $next($request, $response);
});
$app->get('/', function (Request $request, Response $response, array $args) {
return $response->write(file_get_contents(getenv('STATIC_DIR') . '/index.html'));
});
$app->post('/checkout_sessions', function(Request $request, Response $response) use ($app) {
$params = json_decode($request->getBody());
$payment_method_types = [
'usd' => ['card'],
'eur' => ['card'],
'cad' => ['card']
];
$products = [
'cause-a' => 'prod_KP3YP2a3IGYqsb',
'cause-b' => 'prod_KP3iZRGcEjn5W8',
];
$session = \Stripe\Checkout\Session::create([
'success_url' => 'http://localhost:4242/success.html?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => 'http://localhost:4242/?cancel=true',
'mode' => 'payment',
'payment_method_types' => $payment_method_types[$params->currency],
'metadata' => [
'cause' => $params->cause,
'currency' => $params->currency,
],
'submit_type' => 'donate',
'line_items' => [[
'price_data' => [
'currency' => $params->currency,
'product' => $products[$params->cause],
'unit_amount' => $params->amount,
],
'quantity' => 1,
]]
]);
return $response->withJson([
'id' => $session->id
]);
});
$app->get('/order', function (Request $request, Response $response) {
$id = $_GET['sessionId'];
$checkout_session = \Stripe\Checkout\Session::retrieve($id);
echo json_encode($checkout_session);
});
$app->run();
this is the success page with javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Order Confirm</title>
</head>
<body>
<div id="main">
<div id="checkout">
<div id="payment-forum">
<h1>Success</h1>
payment status: <span id="payment-status"></span>
<pre>
</pre>
</div>
</div>
</div>
</body>
<script>
var paymentStatus = document.getElementById('payment-status');
var urlParams = new URLSearchParams(window.location.search);
var sessionId = urlParams.get("session_id")
if (sessionId) {
fetch("/order?sessionId=" + sessionId).then(function(result){
return result.json()
}).then(function(session){
var sessionJSON = JSON.stringify(session, null, 2);
document.querySelector("pre").textContent = sessionJSON;
}).catch(function(err){
console.log('Error when fetching Checkout session', err);
});
}
</script>
</html>
i need help with product detail , customer name , amount on success page and if possible payment paid or not paid status on it.... cant find any tutorial on it or any detail step by step guide on it
i am close but cant get it to bullseyes please help me with it
yeah on success page all i get is payment status and blank
Looks like here is what happened:
Your Checkout Session defined success_url to success.html
Your success.html fired another request to "/success?session_id=xxx"
Your backend handled this with $app->get('/success', function...
It could be confusing to name both HTML in step 2 and the handling URL in step 3 as "success". You may want to use a different name such as "success" and "get-checkout-session" like Stripe example on Github. After that, debug your server log on step 3 to see whether you got the session id correctly and have retrieved the Customer Id.
There is more information to extract from a CheckoutSession. See Stripe's API Reference on available properties. You probably want to expand its payment_intent to see the amount and payment status.
Related
I have to add a list of data structures to a js object on an HTML page.
I have a list of data structures on the server side each identified by a data-key.
A js function loops the list of data-keys
the function gets each structure one at a time from a async_cache using the corresponding data-key.
There may be multiples of same data-keys in the list
if the async_cache doesn't have the data-structure by that data-key it async-fetches and adds it to the cache.
if the async_cache has the data-structure by that data-key it returns it right away.
if the async_cache has already requested a fetch for a data-key and before the data arrives has another request for the same data-key it must not duplicate the request but wait until the data arrives.
I have constructed the following code so far (as an example for discussion). The actual environment can't be shared.
<?php
switch($_GET['--action'] ?? false){
case 'data-structure':{
$data_group = [
'data-01' => ['a' => 'info-01', 'b' => 'extra-01'],
'data-02' => ['a' => 'info-02', 'b' => 'extra-02'],
'data-03' => ['a' => 'info-03', 'b' => 'extra-03'],
'data-04' => ['a' => 'info-04', 'b' => 'extra-04'],
'data-05' => ['a' => 'info-05', 'b' => 'extra-05'],
];
if($data_struct = ($data_group[$_GET['key'] ?? false] ?? false)){
\header('Content-Type: application/json');
echo json_encode(['status'=> 'ok', 'data' => $data_struct], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit();
} else {
http_response_code(404);
echo json_encode('Not Found', JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit();
}
} break;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta key="viewport" content="width=device-width, initial-scale=1.0">
<title>JS Async Data Buffer Experiment</title>
</head>
<body>
<div class="container">
</div>
<script>
xui = {};
xui.async_cache = {
async async_get_await(url = '', options = {}){
// Default options are marked with *
const response = await fetch(
url,
{
method: 'GET', // *GET, POST, PUT, DELETE, etc.
mode: options.mode || 'same-origin', // no-cors, *cors, same-origin
cache: options.cache || 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: options.credintials || 'same-origin', // include, *same-origin, omit
redirect: options.redirect || 'follow', // manual, *follow, error
referrerPolicy: options.referrerPolicy || 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
}
);
return response.json(); // parses JSON response into native JavaScript objects;
},
get(action, key){
if(key in this){
return new Promise((resolve, reject) => {
resolve(this[key]);
});
} else {
return this.async_get_await(
`?--action=${action}&key=${key}`,
).then((r) => {
this[key] = r.data;
return this[key];
});
}
},
};
window.addEventListener('DOMContentLoaded', function(){
var list = [
'data-01',
'data-01',
'data-02',
'data-01',
'data-03',
'data-02',
'data-04',
'data-02',
'data-01',
];
list.forEach((key) => {
console.log({key});
xui.async_cache.get('data-structure', key).then((data) => {
console.log(data);
});
});
});
</script>
</body>
</html>
Case 1 and 2 are taken care of but case 3 is where I am stuck. As you can see the code in the addEventListner executes in one shot before the data is received or event-loop kicks-in. So multiple requests go out for the same data-key.
I am looking for a minimalist approach. If there is a coding feature in JS library without using third party library - that will do as well.
I've also looked into the cache option on the Fetch-API but that is not a solution.
Thanks!
Thanks to #Bergi I finally figured it out!
I rewrote the async_cache and went on simplifying ...
Here is what I got (I've added a few test buttons as well):
<?php
switch($_GET['--action'] ?? false){
case 'data-structure':{
$data_group = [
'data-01' => ['a' => 'info-01', 'b' => 'extra-01'],
'data-02' => ['a' => 'info-02', 'b' => 'extra-02'],
'data-03' => ['a' => 'info-03', 'b' => 'extra-03'],
'data-04' => ['a' => 'info-04', 'b' => 'extra-04'],
'data-05' => ['a' => 'info-05', 'b' => 'extra-05'],
];
if($data_struct = ($data_group[$_GET['key'] ?? false] ?? false)){
\header('Content-Type: application/json');
echo json_encode(['status'=> 'ok', 'data' => $data_struct], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit();
} else {
http_response_code(404);
echo json_encode('Not Found', JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit();
}
} break;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta key="viewport" content="width=device-width, initial-scale=1.0">
<title>JS Async Data Cache Example</title>
</head>
<body>
<div class="container">
<button type="button" onclick="run()">Run</button> <br/>
<button type="button" onclick="delete xui.async_cache['data-01']">Delete 01</button> <br/>
<button type="button" onclick="delete xui.async_cache['data-02']">Delete 02</button> <br/>
<button type="button" onclick="delete xui.async_cache['data-03']">Delete 03</button> <br/>
<button type="button" onclick="delete xui.async_cache['data-04']">Delete 04</button> <br/>
Look at the console for responses and check the network tab as well!
</div>
<script>
xui = {};
xui.async_cache = {
get(key){
return this[key] ?? (this[key] = (fetch(`?--action=data-structure&key=${key}`).then((response) => {
return response.json();
})));
}
};
function run(){
var list = [
'data-01',
'data-01',
'data-02',
'data-01',
'data-03',
'data-02',
'data-04',
'data-02',
'data-01',
];
list.forEach((key) => {
console.log({key});
xui.async_cache.get(key).then((data) => {
console.log(data);
});
});
}
window.addEventListener('DOMContentLoaded', function(){
run();
});
</script>
</body>
</html>
Looks like we can take advantage of the closure's data storage (or caching) inside the promise. And we don't need await or async, atleast for this rudimentary stage.
I have a website where when the user clicks a canvas, he draws on it and it gets pushed into the database. And it draws for every user 10 times in one second.
setInterval(function(){
$.ajax({
url: 'data/canvasSave.php',
success: function(data) {
$('.result').html(data);
console.log(data);
imageCanvas = data;
}
});
let img = new Image();
img.src = imageCanvas;
context.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0 , 0, canvas.width, canvas.height);
}, 100);
Now I notice that this isn't the best way. But is there a good way to check for Database updates?
I tried a few if statements but none of them really worked.
You can use PHP sockets for tracking MySQL Database changes with WebSockets.
Setup Frontend
File: index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MySQL Tracker</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit#3.7.4/dist/css/uikit.min.css" />
</head>
<body>
<div class="uk-container uk-padding">
<h2>Users</h2>
<p>Tracking users table with WebSockets</p>
<table class="uk-table">
<thead>
<tr>
<th>User ID</th>
<th>User Name</th>
</tr>
</thead>
<tbody>
<?php
$connection = mysqli_connect(
'localhost',
'root',
PASSWORD,
DB_NAME
);
$users = mysqli_query($connection, 'SELECT * FROM users');
while ($user = mysqli_fetch_assoc($users)) {
echo '<tr>';
echo '<td>' . $user['id'] . '</td>';
echo '<td>' . $user['name'] . '</td>';
echo '</tr>';
}
?>
</tbody>
</table>
</div>
</body>
</html>
Next, add the PieSocket-JS WebSocket library in your HTML file with the following code:
Now, we are ready to connect to the WebSocket channel and start receiving instantaneous updates from the server. Add the following code to your index.php file to make a websocket connection.
<script>
var piesocket = new PieSocket({
clusterId: 'CLUSTER_ID',
apiKey: 'API_KEY'
});
// Connect to a WebSocket channel
var channel = piesocket.subscribe("my-channel");
channel.on("open", ()=>{
console.log("PieSocket Channel Connected!");
});
//Handle updates from the server
channel.on('message', function(msg){
var data = JSON.parse(msg.data);
if(data.event == "new_user"){
alert(JSON.stringify(data.data));
}
});
</script>
Setup Backend
Let’s create a file called admin.php which adds an entry to the user’s table, every time it is visited.
<?php
$connection = mysqli_connect(
'localhost',
'root',
PASSWORD,
DB_NAME
);
mysqli_query($connection, "INSERT INTO users .....");
?>
The code snippet given above adds an entry in the users table every time its execute either via CLI or from a webserver.
Use the following PHP function to do that.
<?php
function publishUser($event){
$curl = curl_init();
$post_fields = [
"key" => "PIESOCKET_API_KEY",
"secret" => "PIESOCKET_API_SECRET",
"channelId" => "my-channel",
"message" => $event
];
curl_setopt_array($curl, array(
CURLOPT_URL => "https://PIESOCKET_CLUTER_ID.piesocket.com/api/publish",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode($post_fields),
CURLOPT_HTTPHEADER => array(
"Content-Type: application/json"
),
));
$response = curl_exec($curl);
print_r($response);
}
$connection = mysqli_connect(
'localhost',
'root',
PASSWORD,
DB_NAME
);
mysqli_query($connection, "INSERT INTO users .....");
$payload = json_encode([
"event" => "new_user",
"data" => [
"id"=> 1,
"name"=>"Test user"]
]);
publishUser($payload);
?>
Track MySQL changes in real-time with Laravel
For example, in your User model under app/model/User.php add the following code block
public static function boot() {
parent::boot();
static::created(function($user) {
publishUser(json_encode($user));
});
}
Track MySQL changes in real-time with Django
import requests
import json
url = "https://CLUSTER_ID.piesocket.com/api/publish"
payload = json.dumps({
"key": "API_KEY",
"secret": "API_SECRET",
"channelId": 1,
"message": { "text": "Hello world!" }
});
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data = payload)
print(response.text.encode('utf8'))
how can i send variable amount on my line item as it only accept integers please rest everything works but this varible amount is not working tried $params->amount not working
<?php
require_once('vendor/autoload.php');
\Stripe\Stripe::setApiKey('sk_test_key');
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'price_data' => [
'currency' => 'usd',
'product_data' => [
'name' => 'T-shirt',
],
'unit_amount' => 2000,
],
'quantity' => 1,
]],
'mode' => 'payment',
'success_url' => 'https://example.com/success',
'cancel_url' => 'https://example.com/cancel',
]);
?>
<html>
<head>
<title>Buy cool new product</title>
<script src="https://js.stripe.com/v3/"></script>
</head>
<body>
<div class="field">
<label for="amount">Amount to pay</label>
<input type="number" id="amount" step="0.01" value="5.00">
</div>
<button id="checkout-button">Checkout</button>
<script>
var stripe = Stripe('pk_test_51JWkHLK7X12cK8Ptf5y5DQn6Ugf6miu3AqSuhH9wdLsyTB9ouf0TY31vDQxq19xIt6YH76uMTEX1kU9HMyrcEb6w00MTxHnGxc');
var amount = document.getElementById('amount');
const btn = document.getElementById("checkout-button")
btn.addEventListener('click', function(e) {
e.preventDefault();
stripe.redirectToCheckout({
sessionId: "<?php echo $session->id; ?>"
});
})
</script>
</body>
</html>
how can i send variable amount on my line item as it only accept integers please rest everything works but this varible amount is not working tried $params->amount not working
The code to create the payment intent with your secret key needs to be run server-side - you must not use your secret key in client-side code.
You should follow the guide here to see how you can generate a payment intent and provide the secret key in a server rendered template, or you can make an async request to your server from an SPA to get a payment intent client secret. The guide goes through both options.
I use the samples (https://github.com/stripe-samples/checkout-single-subscription/tree/master/server/php) from Stripe to create a subscription. What I don't really understand, how can I pass metadata from my index.html over script.js to the create-checkout-session.php.
I thought I just add data attributes to the index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Stripe</title>
<meta name="description" content="A demo of Stripe Payment Intents" />
<link rel="icon" href="favicon.ico" type="image/x-icon" />
<script src="https://js.stripe.com/v3/"></script>
<script src="./script.js" defer></script>
</head>
<body>
<div class="sr-root">
<div class="sr-main" style="display: flex;">
<div class="sr-container">
<section class="container">
<button id="basic-plan-btn" data-partner="name" data-package="basic">USD 6.90</button>
</section>
<section class="container">
<button id="pro-plan-btn" data-partner="name" data-package="premium">USD 11.90</button>
</section>
</div>
</div>
</div>
</body>
</html>
then I have to read them somehow out in the script.js. But that I don't really figure out how.
// Create a Checkout Session with the selected plan ID
var createCheckoutSession = function(priceId) {
return fetch("/fileadmin/restaurant/stripe/create-checkout-session.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
priceId: priceId,
partner: 'name',
package: 'premium'
})
}).then(function(result) {
return result.json();
});
};
// Handle any errors returned from Checkout
var handleResult = function(result) {
if (result.error) {
var displayError = document.getElementById("error-message");
displayError.textContent = result.error.message;
}
};
/* Get your Stripe publishable key to initialize Stripe.js */
fetch("/fileadmin/restaurant/stripe/config.php")
.then(function(result) {
return result.json();
})
.then(function(json) {
var publishableKey = json.publishableKey;
var basicPriceId = json.basicPrice;
var proPriceId = json.proPrice;
var stripe = Stripe(publishableKey);
// Setup event handler to create a Checkout Session when button is clicked
document
.getElementById("basic-plan-btn")
.addEventListener("click", function(evt) {
createCheckoutSession(basicPriceId).then(function(data) {
// Call Stripe.js method to redirect to the new Checkout page
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(handleResult);
});
});
// Setup event handler to create a Checkout Session when button is clicked
document
.getElementById("pro-plan-btn")
.addEventListener("click", function(evt) {
createCheckoutSession(proPriceId).then(function(data) {
// Call Stripe.js method to redirect to the new Checkout page
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(handleResult);
});
});
});
by that I receive them in the create-checkout-session.php
<?php
require_once 'shared.php';
$domain_url = $config['domain'];
$checkout_session = \Stripe\Checkout\Session::create([
'success_url' => $domain_url . 'success.php?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => $domain_url . 'canceled.php',
'payment_method_types' => ['card'],
'mode' => 'subscription',
'allow_promotion_codes' => true,
'line_items' => [[
'price' => $body->priceId,
'quantity' => 1,
]],
'subscription_data' => ['trial_period_days' => 60],
'metadata' => [
'partner' => $body->partner,
'package' => $body->package
],
]);
echo json_encode(['sessionId' => $checkout_session['id']]);
Thank You.
What you've done adding to the JSON body of the fetch call looks right to me. If you're trying to set the 'name' and 'premium' values dynamically from some input, then take a look at this previous answer for some approaches for getting input values.
I am new to PHP and MySQL, so this task really keeps me struggling:
I have an MySQL database which contains a lot of geo coordinates which shall be extracted by php, transformed to JSON format to pass them to JavaScript and then be displayed in Leaflet's heatmap.
I already wrote the JS code, and the AJAX seems to be functioning. But Heatmap does not seem to be accepting my array containing the coordinates. I can't see where I made an mistake; I think my PHP array is not formatted in the right way.
Heatmap needs to get its data in this format:
var testData = {
max: 8,
data: [{lat: 24.6408, lng:46.7728, count: 1},{lat: 50.75, lng:-1.55, count: 1}, ...]
};
This is my code by now:
var geoData;
function loadData() {
alert("loading Data");
getJSON();
}
function getJSON() {
$.ajax({
url: "assets/php/readGeoData.php",
type: "GET",
datatype: "json",
success: function(data) {
alert("ajax transfer successful ");
geoData = data;
//For debugging:
alert(getGeoData());
}
})
}
function getGeoData() {
return geoData;
}
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.2.0/dist/leaflet.css" integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ==" crossorigin="" />
<!-- Leaflet JS -->
<script src="https://unpkg.com/leaflet#1.2.0/dist/leaflet.js" integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log==" crossorigin=""></script>
<!-- Leaflet Heatmap JS -->
<script src="assets/js/Leaflet.heat-gh-pages/dist/leaflet-heat.js"></script>
<!-- map CSS -->
<link rel="stylesheet" href="assets/css/map.css" />
<!-- map JS -->
<script src="assets/js/mymap.js"></script>
<!-- main CSS -->
<link rel="stylesheet" href="assets/css/main.css" />
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- data JS -->
<script src="assets/js/loadGeoData.js"></script>
</head>
<body>
<h1>movementprofile</h1>
<button id="importButton">import geoData</button>
<div id="mapid"></div>
<script>
$("#importButton").click(function() {
loadData();
});
</script>
<!-- creating the map -->
<script>
var mymap = L.map('mapid').setView([51.25, 10.5], 6);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=' + mapboxToken, {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.streets'
}).addTo(mymap);
</script>
<script>
var heatmapData = {
max: 8,
data: getGeoData()
};
var heatmapLayer = new HeatmapOverlay(cfg);
heatmapLayer.setData(8, getGeoData());
</script>
</body>
</html>
PHP:
<?php
$db = new PDO('mysql:host=127.0.0.1;dbname=movementprofile;', 'root', *****);
$query ='SELECT longitude, latitude FROM movementprofile WHERE longitude IS NOT NULL AND latitude IS NOT NULL';
foreach ($db->query($query) as $row) {
print_r($row);
$longitude = $row['longitude'];
$latitude = $row['latitude'];
$singleDataset = array('lon' => $longitude,'lat' => $latitude, 'count'=> 1);
array_push($datasets,$singleDataset, JSON_FORCE_OBJECT);
echo json_encode($datasets);
}
This is the array I get right now (in the JS alert box):
Array
(
[longitude] => 13.39611111
[0] => 13.39611111
[latitude] => 52.52944444
[1] => 52.52944444
)
nullArray
(
[longitude] => 13.37472222
[0] => 13.37472222
[latitude] => 52.53027778
[1] => 52.53027778
)
nullArray
(
[longitude] => 13.38361111
[0] => 13.38361111
[latitude] => 52.53
[1] => 52.53
)
//... and so on, there are more than 30.000 entries
So, how do I get this array to look like the one Heatmap needs?
EDIT:
So I edited my PHP to this:
foreach ($db->query($query) as $row) {
print_r($row);
$longitude = $row['longitude'];
$latitude = $row['latitude'];
$singleDataset = array('lon' => $longitude,'lat' => $latitude, 'count'=> 1);
array_push($datasets,json_encode($singleDataset));
But still got this array:
Array
(
[longitude] => 13.39611111
[0] => 13.39611111
[latitude] => 52.52944444
[1] => 52.52944444
)
//and so on
# thinsoldier
Did you mean that?
First thing I see in your code is that you do print_r($row); - remove or comment that.
Also maybe take a look at my php connector how to create geojson (example connects with postgres but you can simply rewrite that to mysql and adjust to your database structure):
<?php
$dbconn = pg_connect("host=localhost port=5432 dbname=pguser user=pguser password=pass");
$result = pg_query($dbconn, "SELECT * FROM test");
$geojson = array(
'type' => 'FeatureCollection',
'features' => array()
);
while($row = pg_fetch_assoc($result)) {
$feature = array(
'id' => $row['id'],
'type' => 'Feature',
'geometry' => array(
'type' => 'Point',
'coordinates' => array($row['latitude'], $row['longitude'])
),
# Pass other attribute columns here
'properties' => array(
'test' => 'test',
'column1' => $row['column1'],
'column2' => $row['column2']
)
);
# Add feature arrays to feature collection array
array_push($geojson['features'], $feature);
}
header('Content-type: application/json');
echo json_encode($geojson, JSON_NUMERIC_CHECK);
?>
EDIT
Because you want to get specific structure of json, not geoJson with features, above code may be simplified to:
....
$json = array(
'max' => '8',
'data' => array()
);
while($row = pg_fetch_assoc($result)) {
$data = array(
'lat' => $row['latitude'],
'lng' => $row['longitude'],
'count' => '1',
);
# Add feature arrays to feature collection array
array_push($json['data'], $data);
}
header('Content-type: application/json');
echo json_encode($json, JSON_NUMERIC_CHECK);
....