So I have a wordpress Ajax function that retrieves MySQL data as JSON and logs it. However I want to not directly get the data back on the page where my AJAX function is, but I want to save the data to a JSON file instead, so I can use it for a wider variety of purposes.
Here is my AJAX function:
$.get(
ajax_url,
data,
function(data) { // AJAX callback
fill_json(data);
}// End AJAX callback
);
The fill_json() is a function to echo the JSON data in a table I wrote myself.
Now here is what happens inside my AJAX hook:
$sql_search = $wpdb->get_results(" a complicated mysql search here ");
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$result = json_encode($result);
echo $result;
} else {
header("Location: ".$_SERVER["HTTP_REFERER"]);
}
underneath echo $result; in my Ajax hook I tried the following piece of code, but I don't know how I can see if it worked or not:
$json_path = "/var/www/vhosts/jtc.ae/httpdocs/pre/wp/wp-content/themes/Amazing_japan_HP/new/search.json";
file_put_contents($json_path, $result);
My question:
Is this the correct way to save the data to a JSON file, and how can I get this data on my main page then?
Extra question: Will saving $result to a JSON file conflict with multiple users using the AJAX at the same time?
All you did is right .. please make sure the steps below :
Pass write permission to the folder /new inside "Amazing_japan_HP" (chmod -R 666 /new)
To save the data in file use file_put_contents($file, $current);
To get the data from the file use $current = file_get_contents($file);
For all newly created files try to use umask. It provides required permission to the files for writing content in it
umask() sets PHP's umask to mask & 0777 and returns the old umask.
When PHP is being used as a server module, the umask is restored when
each request is finished.
Related
The instructions in clickfunnels as me to start by creating a test endpoint URL:
. Creating A Test Endpoint.
First, you will need to create a test endpoint at <your-domain/funnel_webhooks/test>
And it should include the headers below.
Content-Type as application/json
X-Clickfunnels-Webhook-Delivery-Id as an MD5 of the URL and Payload.
The payload (HTTP message body) will be a JSON object with a key of "time" and value of the current time in UTC as follows:
{ "time": "YYYY-MM-DD HH:MM:SS UTC" }
I went into the file manager in my hosting and added a folder for funnel_webhooks & a file called test.
I think I changed the content type to JSON
And, I think I figured out how to create the JSON object within the file.
I'm not sure how to do this part:
X-Clickfunnels-Webhook-Delivery-Id as an MD5 of the URL and Payload.
This loom video will show where I'm at so far in the process.
https://www.loom.com/share/1c9be96014b8413a8c9ba54f56dd42a8
Any support would be greatly appreciated!
It's actually much more simple than you think. They just want to verify you own the domain by getting a 200 response from any file you place in the folder on your server.
Create this folder structure on your server in the root and add an index.php file or index.html file like this:
/funnel_webhooks/test/index.php (I wrote "hello" in this file for good measure)
Go to Click Funnels. Click your Funnel. Click Settings. Scroll to bottom and click Manage Your Funnel Webhooks
Create a New webhook with the URL: whateveryourdomain/funnel_webhooks/test/index.php
Click Create Funnel Webhook Button
If your file is in the right location then click funnels will use this to verify you own the domain.
All of your webhooks going forward will work with no problem as long as you use this domain that was verified.
let me give it a try!
What you are doing right now is just creating a JSON file that is not going to get the webhook event from the clickfunnel.
Start by creating a PHP file if your server is compatible with PHP.
And in it just write this code and try it out.
<?php
//set the headers.
header("Content-Type: application/json;");
header("X-Clickfunnels-Webhook-Delivery-Id : MD5 of CONTENTS HERE");
//check if there is input data.
if ($json = json_decode(file_get_contents("php://input"), true)) {
//print and set the data as variable
print_r($json);
$data = $json;
}else{
//try getting the POST data.
print_r($_POST);
$data = $_POST;
}
//set the response as OK - 200
http_response_code(200); //response code for OK.
echo json_encode(array("status" => 'OK', "code" => 1, "payload" => $data));
//save the data as a file to check the information that was sent by the webhook.
$file = 'webhook_contents.txt';
$current = file_get_contents($file);
$current .= date("Y-m-d h:i:s").json_encode($data);
file_put_contents($file, $current);
// From here, it all depends on what you want to do with the webhook event data.
?>
this code should give you the Headers to get a JSON payload, and echo a response of said payload.
At the same time it should create a file with the name "webhook_contents.txt" in which you should be able to read the webhook event payload.
Let me know if it works!
My web-application should be able to store and update (also load) JSON data on a Server.
However, the data may contain some big arrays where every time they are saved only a new entry was appended.
My solution:
send updates to the server with a key-path within the json data.
Currently I'm sending the data with an xmlhttprequest by jquery, like this
/**
* Asynchronously writes a file on the server (via PHP-script).
* #param {String} file complete filename (path/to/file.ext)
* #param content content that should be written. may be a js object.
* #param {Array} updatePath (optional), json only. not the entire file is written,
* but the given path within the object is updated. by default the path is supposed to contain an array and the
* content is appended to it.
* #param {String} key (optional) in combination with updatePath. if a key is provided, then the content is written
* to a field named as this parameters content at the data located at the updatePath from the old content.
*
* #returns {Promise}
*/
io.write = function (file, content, updatePath, key) {
if (utils.isObject(content)) content = JSON.stringify(content, null, "\t");
file = io.parsePath(file);
var data = {f: file, t: content};
if (typeof updatePath !== "undefined") {
if (Array.isArray(updatePath)) updatePath = updatePath.join('.');
data.a = updatePath;
if (typeof key !== "undefined") data.k = key;
}
return new Promise(function (resolve, reject) {
$.ajax({
type: 'POST',
url: io.url.write,
data: data,
success: function (data) {
data = data.split("\n");
if (data[0] == "ok") resolve(data[1]);
else reject(new Error((data[0] == "error" ? "PHP error:\n" : "") + data.slice(1).join("\n")));
},
cache: false,
error: function (j, t, e) {
reject(e);
//throw new Error("Error writing file '" + file + "'\n" + JSON.stringify(j) + " " + e);
}
});
});
};
On the Server, a php script manages the rest like this:
recieves the data and checks if its valid
check if the given file path is writable
if the file exists and is .json
read it and decode the json
return an error on invalid json
if there is no update path given
just write the data
if there is an update path given
return an error if the update path in the JSON data can't be traversed (or file didn't exist)
update the data at update-path
write the pretty-printed json to file
However I'm not perfectly happy and problems kept coming for the last weeks.
My Questions
Generally: How would you approach this problem? alternative suggestions, databases? any libraries that could help?
Note: I would prefer solutions, that just use php or some standart apache stuff.
One problem was, that sometimes, multiple writes on the same file were triggered. To avoid this I used the Promises (wrapped it because I read jquerys deferred stuff isnt Promise/A compliant) client side, but I dont feel 100% sure it is working. Is there a (file) lock in php that works across multiple requests?
Every now and then the JSON files break and its not clear to me how to reproduce the problem. At the time it breaks, I don't have a history of what happened. Any general debugging strategies with a client/server saving/loading process like this?
I wrote a comet enable web server that does diffs on updates of json data structures. For the exactly same reason. The server keeps a few version of a json document and serves client with different version of the json document with the update they need to get to the most reason version of the json data.
Maybe you could reuse some of my code, written in C++ and CoffeeScript: https://github.com/TorstenRobitzki/Sioux
If you have concurrent write accesses to your data structure, are your sure, that who ever writes to the file has the right version of the file in mind when reading the file?
is this possible?
To get the JSON (plugin url) of the form (fields, input types, etc.) how would I have to hook this up in a plugin?
Then to use the send mechanism of the plugin how would I transfer my rest POST to the plugins send function?
Any ideas would be appreciated
You can hook in the wpcf7_before_send_mail action to get POST data right before the mail il sent by CF7.
add_action('wpcf7_before_send_mail', 'my_wpcf7_choose_recipient');
function my_wpcf7_choose_recipient($WPCF7_ContactForm)
{
// use $submission to access POST data
$submission = WPCF7_Submission::get_instance();
$data = $submission->get_posted_data();
$subject = $data['subject']
// use WPCF7_ContactForm->prop() to access form settings
$mail = $WPCF7_ContactForm->prop('mail');
$recipient = $mail['recipient'];
// update a form property
$WPCF7_ContactForm->set_properties(array('mail' => $mail));
}
Then in this function you can call your plugin and transfer him $submission.
And if you want to alter the POST data, you can use the wpcf7_posted_data filter:
add_filter('wpcf7_posted_data', 'my_wpcf7_posted_data');
function my_wpcf7_posted_data($data)
{
$data['subject'] = 'Test ' . $data['subject'];
return $data;
}
I know this is two years old, but I needed the same exact thing so I made a plugin and happened to run across this post.
https://github.com/CodeBradley/contact-form-7-rest-api
I would like to know what can I do to upload attachments in CouchDB using the update function.
here you will find an example of my update function to add documents:
function(doc, req){
if (!doc) {
if (!req.form._id) {
req.form._id = req.uuid;
}
req.form['|edited_by'] = req.userCtx.name
req.form['|edited_on'] = new Date();
return [req.form, JSON.stringify(req.form)];
}
else {
return [null, "Use POST to add a document."]
}
}
example for remove documents:
function(doc, req){
if (doc) {
for (var i in req.form) {
doc[i] = req.form[i];
}
doc['|edited_by'] = req.userCtx.name
doc['|edited_on'] = new Date();
doc._deleted = true;
return [doc, JSON.stringify(doc)];
}
else {
return [null, "Document does not exist."]
}
}
thanks for your help,
It is possible to add attachments to a document using an update function by modifying the document's _attachments property. Here's an example of an update function which will add an attachment to an existing document:
function (doc, req) {
// skipping the create document case for simplicity
if (!doc) {
return [null, "update only"];
}
// ensure that the required form parameters are present
if (!req.form || !req.form.name || !req.form.data) {
return [null, "missing required post fields"];
}
// if there isn't an _attachments property on the doc already, create one
if (!doc._attachments) {
doc._attachments = {};
}
// create the attachment using the form data POSTed by the client
doc._attachments[req.form.name] = {
content_type: req.form.content_type || 'application/octet-stream',
data: req.form.data
};
return [doc, "saved attachment"];
}
For each attachment, you need a name, a content type, and body data encoded as base64. The example function above requires that the client sends an HTTP POST in application/x-www-form-urlencoded format with at least two parameters: name and data (a content_type parameter will be used if provided):
name=logo.png&content_type=image/png&data=iVBORw0KGgoA...
To test the update function:
Find a small image and base64 encode it:
$ base64 logo.png | sed 's/+/%2b/g' > post.txt
The sed script encodes + characters so they don't get converted to spaces.
Edit post.txt and add name=logo.png&content_type=image/png&data= to the top of the document.
Create a new document in CouchDB using Futon.
Use curl to call the update function with the post.txt file as the body, substituting in the ID of the document you just created.
curl -X POST -d #post.txt http://127.0.0.1:5984/mydb/_design/myddoc/_update/upload/193ecff8618678f96d83770cea002910
This was tested on CouchDB 1.6.1 running on OSX.
Update: #janl was kind enough to provide some details on why this answer can lead to performance and scaling issues. Uploading attachments via an upload handler has two main problems:
The upload handlers are written in JavaScript, so the CouchDB server may have to fork() a couchjs process to handle the upload. Even if a couchjs process is already running, the server has to stream the entire HTTP request to the external process over stdin. For large attachments, the transfer of the request can take significant time and system resources. For each concurrent request to an update function like this, CouchDB will have to fork a new couchjs process. Since the process runtime will be rather long because of what is explained next, you can easily run out of RAM, CPU or the ability to handle more concurrent requests.
After the _attachments property is populated by the upload handler and streamed back to the CouchDB server (!), the server must parse the response JSON, decode the base64-encoded attachment body, and write the binary body to disk. The standard method of adding an attachment to a document -- PUT /db/docid/attachmentname -- streams the binary request body directly to disk and does not require the two processing steps.
The function above will work, but there are non-trivial issues to consider before using it in a highly-scalable system.
I'm working on a RESTful application using CodeIgniter and I'm unable to access my POST'd json data in my controller.
I'm posting the json via cURL on my local machine, while the app is being developed on a remote server.
Here is the controller code in question:
class Products extends CI_Controller
{
public function __construct()
{
$this->load->model(products_model);
}
public function index($id = FALSE)
{
if($_SERVER['REQUEST_METHOD'] == 'GET')
{
// fetch product data
$product_data = $this->products_model->get_products($id)
// set appropriate header, output json
$this->output
->set_content_type(application/json)
->set_output(json_encode($product_data));
}
elseif($_SERVER['REQUEST_METHOD'] == 'POST')
{
// debugging for now, just dump the post data
var_dump($this->input->post());
}
}
}
The GET action is working well enough, and returning the appropriate data when requested from a browser, or via a cURL request. However, when attempting to POST json data via cURL I consistently get bool(FALSE) returned from the POST section of the index function. Here is the cURL request I'm making:
curl -X POST -d #product.json mydomain.com/restfulservice/products
Also, here is the contents of the product.json file:
{"id":"240",
"name":"4 x 6 Print",
"cost":"1.5900",
"minResolution":401,
"unitOfMeasure":"in",
"dimX":0,
"dimY":0,
"height":4,
"width":6}
I've made another POST via cURL, excluding the json data and passing something like this:
curl -X POST -d '&this=that' mydomain.com/restfulservice/products
Which returns
array(1) {
["this"]=>
string(4) "that"
}
What gives? Something with the json? It's valid. I've turned off the global CSRF and XSS in application/config/config.php as I understand they require use of CI's form_open() and won't work properly without it. It's my understanding that excluding parameters from $this->input->post() will return ALL the post items yet I continue to get none. I've also tried going around CI's input library and accessing the data via PHP's $_POST variable, it has made no difference.
Your post data is not in query string format so you should skip dealing with $_POST and go straight to the raw post data.
try
var_dump($HTTP_RAW_POST_DATA);
or even better
var_dump(file_get_contents("php://input"));
in codeigniter 2.X, you can override Input class and add necessary functionality.
https://ellislab.com/codeigniter/user-guide/general/core_classes.html
add file MY_Input.php to application/core
add code inside this file:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Input extends CI_Input {
public function raw_post() {
return file_get_contents('php://input');
}
public function post($index = NULL, $xss_clean = FALSE) {
$content_type = $this->get_request_header('Content-type');
if (stripos($content_type, 'application/json') !== FALSE
&& ($postdata = $this->raw_post())
&& in_array($postdata[0], array('{', '['))) {
$decoded_postdata = json_decode($postdata, true);
if ((json_last_error() == JSON_ERROR_NONE))
$_POST = $decoded_postdata;
}
return parent::post($index, $xss_clean);
}
}
that's it..
use it like normal post..