How to upload picture to mattermost server by using libcurl? - c++

Trying to build a C++ application to upload images to mattermost server(version 5.14.0).And I have get access token,channel id by using my C++ code.But I can't upload image by using libcurl.
This is my CPP code(using libcurl right now):
void uploadPicture(string url,string channelId, string path,string fileName,string token)
{
url += "/api/v4/files";
CURL *curl;
struct curl_httppost *formpost = NULL;
struct curl_httppost *lastptr = NULL;
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "files",
CURLFORM_FILE, path.c_str(),
CURLFORM_FILENAME,"test.jpg",
CURLFORM_CONTENTTYPE, "image/jpeg",
CURLFORM_END);
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "client_ids",
CURLFORM_COPYCONTENTS, "test.jpg",
CURLFORM_END);
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "channel_id",
CURLFORM_COPYCONTENTS, channelId.c_str(),
CURLFORM_END);
struct curl_slist *headers = NULL;
string auth = "Authorization:Bearer ";
auth += token;
headers = curl_slist_append(headers, "Content-Type:multipart/form-data");
headers = curl_slist_append(headers, auth.c_str());
CURLcode res;
curl = curl_easy_init();
if (curl)
{
res = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_setopt(curl, CURLOPT_HTTPPOST,formpost);
res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, getFileInfo);
res = curl_easy_setopt(curl, CURLOPT_POST, 1);
res = curl_easy_perform(curl);
if (res != 0)
{
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
}
}
But it won't work...Please tell me where the problem is.

At last.I find a solution:
void uploadByMimeApi(string url, string channelId, string path, string fileName, string token)
{
url += "/api/v4/files";
CURL *curl = curl_easy_init();
curl_mime *mime;
curl_mimepart *part;
curl_mimepart *part2;
curl_mimepart *part3;
/* Build an HTTP form */
mime = curl_mime_init(curl);
part = curl_mime_addpart(mime);
curl_mime_name(part, "files");
curl_mime_filedata(part, path.c_str());
curl_mime_type(part, "image/jpeg");
part2 = curl_mime_addpart(mime);
curl_mime_data(part2, channelId.c_str(), CURL_ZERO_TERMINATED);
curl_mime_name(part2, "channel_id");
part3 = curl_mime_addpart(mime);
curl_mime_data(part3, "test", CURL_ZERO_TERMINATED);
curl_mime_name(part3, "client_ids");
//header issue
struct curl_slist *headers = NULL;
static const char buf[] = "Expect:";
string auth = "Authorization:Bearer ";
auth += token;
headers = curl_slist_append(headers, auth.c_str());
headers = curl_slist_append(headers, buf);
/* Post and send it. */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, getFileInfo);
curl_easy_perform(curl);
/* Clean-up. */
curl_easy_cleanup(curl);
curl_mime_free(mime);
}

Related

How to stop AppInsights flattening array of strings from a simple http post

I am trying to send data to AppInsights from cpp as a simple piece of json. But, AppInsights insists of flattening my array of strings into a comma separated string.
For example, if the post body is this:
{
"data": {
"baseData": {
"name": "UWMLicensing",
"properties": {
"myValues": ["1", "2"]
},
"ver": "2"
},
"baseType": "EventData"
},
"iKey": "<iKey>",
"name": "Event",
"time": "2021-09-15T17:00:16Z"
}
This arrives in AppInsights as a customEvent with the customDimensions set to the myValues property. However, the customDimensions data is set to:
{"myValues": "1, 2"}
I'd like AppInsights to leave the array alone and for the customDimensions be set to:
{"myValues": ["1", "2"]}
How can I convince AppInsights to not flatten my array and leave the data as it was?
My test app uses libcurl:
int main(void)
{
CURL *curl;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
const char *line =
"{"
"\"data\": {"
"\"baseData\": {"
"\"name\": \"UWMLicensing\","
"\"properties\": {"
"\"array\": [\"1\", \"2\"]"
"},"
"\"ver\": \"2\""
"},"
"\"baseType\": \"EventData\""
"},"
"\"iKey\": \"<YOUR_INSTRUMENTATION_KEY>\","
"\"name\": \"Event\","
"\"time\": \"%s\""
"}";
char json[255];
sprintf_s(json, 255, line, getTime().c_str());
struct curl_slist *list = NULL;
list = curl_slist_append(list, "Content-Type: application/json; charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_URL, "https://dc.services.visualstudio.com/v2/track");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json);
curl_easy_perform(curl);
curl_slist_free_all(list);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
Posting the comment as an answer to help other community members
In the below code the string what you are using use it as a log in the application insights instead of using it as an array as because the strings are the default values of application insights internally.
int main(void)
{
CURL *curl;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
const char *line =
"{"
"\"data\": {"
"\"baseData\": {"
"\"name\": \"UWMLicensing\","
"\"properties\": {"
"\"array\": [\"1\", \"2\"]"
"},"
"\"ver\": \"2\""
"},"
"\"baseType\": \"EventData\""
"},"
"\"iKey\": \"<YOUR_INSTRUMENTATION_KEY>\","
"\"name\": \"Event\","
"\"time\": \"%s\""
"}";
char json[255];
sprintf_s(json, 255, line, getTime().c_str());
struct curl_slist *list = NULL;
list = curl_slist_append(list, "Content-Type: application/json; charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_URL, "https://dc.services.visualstudio.com/v2/track");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json);
curl_easy_perform(curl);
curl_slist_free_all(list);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}

cURL POST request in C++

I have cURL https request I am trying to send to my web server in a C++ program. I am getting back a "Bad Request" format response.
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl)
{
int res = 0;
snprintf(curl_url, sizeof(curl_url), "https://%s:8080/hello", results);
snprintf(curl_fields, sizeof(curl_fields),"\"name\":\"%s\", \"key\":\"%s\"", name, data);
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charset: utf-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_URL, curl_url);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, curl_fields);
res = curl_easy_perform(curl);
if ( res )
{
---error---
}
curl_easy_cleanup(curl);
curl_global_cleanup();
}
Can I get some help ?
Are you trying to send the following json?
{
"name": name,
"data": data
}
from this line of code
snprintf(curl_fields, sizeof(curl_fields),"\"name\":\"%s\", \"key\":\"%s\"", name, data);
shouldn't it then be
snprintf(curl_fields, sizeof(curl_fields),"{\"name\":\"%s\", \"key\":\"%s\"}", name, data);
(add the curly braces)

Uploading files in a forum with a Web Service in Moodle

I need to upload files into a forum in moodle through Web Services, I have been searching and I found that exist a WS called core_files_upload(). I looked at the code of this WS and the context level of this WS is only (block, course, coursecat, system, user or module), the context forum not exist and this WS is deprecated.
I also found that in Moodle 3.0 there are 2 new WS related to forums, they are mod_forum_add_discussion and mod_forum_add_discussion_post but I also looked at the code and they don't allow upload.
Then I decided that the best solution would be to create a new one, but I don't know much about uploading files in Moodle and can't find much information. I'm a little bit familiar with the structure of the WS in Moodle because I have made 2 very simple WS but I don't know how to do this.
If anyone knows how to do it or have any examples or documentation that may be useful, it would be helpful.
Thanks in advance.
You can look up for the file
/webservice/upload.php
this file is for uploading files
$params = array('token'=>$token, 'filepath' => $filepath
, 'filearea'=>'draft') + $_FILES ;
$serverurl = <domainname>. '/webservice/upload.php'. '?token=' . $token;
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_VERBOSE, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
curl_setopt($ch, CURLOPT_URL, $serverurl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$response = curl_exec($ch);
or this can code can help you, that will create a file in moodle data and record in file table from temp file.
$fs = get_file_storage();
$target_path = <target-path>;
$context = get_context_instance(CONTEXT_USER, $userID, MUST_EXIST);
$cm = get_coursemodule_from_instance('forum', $forum->id);
$modcontext = context_module::instance($cm->id, MUST_EXIST);
//saving in draft
$item = rand();
$file_record = array('contextid'=>$context->id, 'component'=>'user', 'filearea'=>'draft', 'itemid'=>$item,
'filepath'=>"/", 'filename'=><filename>, 'userid'=>$userID);
$fs->create_file_from_pathname($file_record, $CFG->dirroot."/".$target_path.<filename>);
// saving for post
$file_record = array('contextid'=>$modcontext->id, 'component'=>'mod_forum', 'filearea'=>'post', 'itemid'=>$post->id,
'filepath'=>"/", 'filename'=><filename>, 'userid'=>$userID);
$fs->create_file_from_pathname($file_record, $CFG->dirroot."/".$target_path.$imagefileEnc);
At the request of #insightful i I'm going to publish my code, I hope this helps somebody
First the externallib.php of the WS
externallib.php
require_once($CFG->libdir . "/externallib.php");
require_once($CFG->libdir . "/filelib.php");
class local_upload_tfg_external extends external_api {
/**
* Returns description of method parameters
* #return external_function_parameters
*/
public static function upload_tfg_parameters() {
return new external_function_parameters(
array('community_key' => new external_value(PARAM_TEXT, 'Comunidad a la que se subira el TFG o TFM.', VALUE_REQUIRED, '', NULL_NOT_ALLOWED),
'username' => new external_value(PARAM_TEXT, 'Usuario que sube el archivo.', VALUE_REQUIRED, '', NULL_NOT_ALLOWED),
'folder_name' => new external_value(PARAM_TEXT, 'Directorio donde se subira el archivo.', VALUE_REQUIRED, '', NULL_NOT_ALLOWED))
);
}
public static function upload_tfg($community_key, $username, $folder_name) {
global $CFG, $DB, $USER;
require_once($CFG->dirroot . "/mod/forum/lib.php");
$params = self::validate_parameters(self::upload_tfg_parameters(),
array(
'community_key' => $community_key,
'username' => $username,
'folder_name' => $folder_name
));
//Context validation
//OPTIONAL but in most web service it should present
$contextoUser = get_context_instance(CONTEXT_USER, $USER->id);
self::validate_context($contextoUser);
$fs = get_file_storage();
$warnings = array();
//We get the course to which the file must be uploaded
$sql = "SELECT id FROM mdl_course WHERE idnumber = ?";
$result = $DB->get_records_sql($sql, array($community_key));
foreach ( $result as $n ) {
$courseid = $n->id;
}
if( is_null($courseid)){
throw new moodle_exception('no_course','No existe el curso');
}
//e get the forum to upload the file
$sql = "SELECT f.id FROM mdl_forum f , mdl_course c WHERE c.idnumber = ? AND c.id = f.course AND f.name = ?";
$result = $DB->get_records_sql($sql, array($community_key, $folder_name));
foreach ( $result as $n ) {
$forumid = $n->id;
}
if( is_null($forumid)){
throw new moodle_exception('no_forum','No existe el foro');
}
//We get the user who wants to upload the file
$sql = "SELECT id FROM mdl_user WHERE username = ?";
$result = $DB->get_records_sql($sql, array($username));
foreach ( $result as $n ) {
$userid = $n->id;
}
if( is_null($userid)){
throw new moodle_exception('no_user','No existe el usuario');
}
//We check if the user belongs to the course
$contextCourse = context_course::instance($courseid);
$enrolled = is_enrolled($contextCourse, $userid, '', true);
if( !$enrolled){
throw new moodle_exception('user_no_enrolled','El usuario no está en el curso');
}
//Files received
$numFiles = count($_FILES);
if($numFiles > 0){
// Request and permission validation.
$forum = $DB->get_record('forum', array('id' => $forumid), '*', MUST_EXIST);
list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum');
$context = context_module::instance($cm->id);
self::validate_context($context);
// Normalize group.
if (!groups_get_activity_groupmode($cm)) {
// Groups not supported, force to -1.
$groupid = -1;
} else {
// Check if we receive the default or and empty value for groupid,
// in this case, get the group for the user in the activity.
if ($groupid === -1 ) {
$groupid = groups_get_activity_group($cm);
} else{
$groupid = -1;
}
}
if (!forum_user_can_post_discussion($forum, $groupid, -1, $cm, $context)) {
throw new moodle_exception('cannotcreatediscussion', 'forum');
}
$thresholdwarning = forum_check_throttling($forum, $cm);
forum_check_blocking_threshold($thresholdwarning);
foreach ($_FILES as $fieldname=>$uploaded_file) {
// check upload errors
if (!empty($_FILES[$fieldname]['error'])) {
switch ($_FILES[$fieldname]['error']) {
case UPLOAD_ERR_INI_SIZE:
throw new moodle_exception('upload_error_ini_size', 'repository_upload');
break;
case UPLOAD_ERR_FORM_SIZE:
throw new moodle_exception('upload_error_form_size', 'repository_upload');
break;
case UPLOAD_ERR_PARTIAL:
throw new moodle_exception('upload_error_partial', 'repository_upload');
break;
case UPLOAD_ERR_NO_FILE:
throw new moodle_exception('upload_error_no_file', 'repository_upload');
break;
case UPLOAD_ERR_NO_TMP_DIR:
throw new moodle_exception('upload_error_no_tmp_dir', 'repository_upload');
break;
case UPLOAD_ERR_CANT_WRITE:
throw new moodle_exception('upload_error_cant_write', 'repository_upload');
break;
case UPLOAD_ERR_EXTENSION:
throw new moodle_exception('upload_error_extension', 'repository_upload');
break;
default:
throw new moodle_exception('nofile');
}
}
/*$file = new stdClass();
$file->filename = clean_param($_FILES[$fieldname]['name'], PARAM_FILE);
// check system maxbytes setting
if (($_FILES[$fieldname]['size'] > get_max_upload_file_size($CFG->maxbytes))) {
// oversize file will be ignored, error added to array to notify web service client
$file->errortype = 'fileoversized';
$file->error = get_string('maxbytes', 'error');
} else {
$file->filepath = $_FILES[$fieldname]['tmp_name'];
// calculate total size of upload
//$totalsize += $_FILES[$fieldname]['size'];
}
$files[] = $file;*/
$filename = $_FILES[$fieldname]['name'];
$filepath = $_FILES[$fieldname]['tmp_name'];
// Create the discussion.
$discussion = new stdClass();
$discussion->course = $course->id;
$discussion->forum = $forum->id;
$discussion->message = "<p>".$filename."</p>";
$discussion->messageformat = FORMAT_HTML; // Force formatting for now.
$discussion->messagetrust = trusttext_trusted($context);
$discussion->itemid = 0;
$discussion->groupid = $groupid;
$discussion->mailnow = 0;
$discussion->subject = $filename;
$discussion->name = $discussion->subject;
$discussion->timestart = 0;
$discussion->timeend = 0;
if ($discussionid = forum_add_discussion($discussion)) {
$discussion->id = $discussionid;
//We update the user of the discursion to the one of the user received
$sql = "UPDATE mdl_forum_discussions SET userid= ? WHERE id = ?";
$DB->execute($sql, array($userid, $discussionid));
/*
// Trigger events and completion.
$params = array(
'context' => $context,
'objectid' => $discussion->id,
'other' => array(
'forumid' => $forum->id,
)
);
$event = \mod_forum\event\discussion_created::create($params);
$event->add_record_snapshot('forum_discussions', $discussion);
$event->trigger();
$completion = new completion_info($course);
if ($completion->is_enabled($cm) && ($forum->completiondiscussions || $forum->completionposts)) {
$completion->update_state($cm, COMPLETION_COMPLETE);
}
$settings = new stdClass();
$settings->discussionsubscribe = false; //discussionsubscribe (bool); subscribe to the discussion?, default to true
forum_post_subscription($settings, $forum, $discussion
//se guardara el fichero
// Get any existing file size limits.
//$maxareabytes = FILE_AREA_MAX_BYTES_UNLIMITED;
//$maxupload = get_user_max_upload_file_size($context, $CFG->maxbytes);
// Check the size of this upload.
//if ($maxupload !== USER_CAN_IGNORE_FILE_SIZE_LIMITS && $totalsize > $maxupload) {
// throw new file_exception('userquotalimit');
//}
*/
//We get the course to which the file must be uploaded
$sql = "SELECT id FROM mdl_forum_posts WHERE discussion = ? ORDER BY id ASC LIMIT 1";
$result = $DB->get_records_sql($sql, array($discussionid));
foreach ( $result as $n ) {
$postid = $n->id;
}
if( is_null($postid)){
throw new moodle_exception('no_post','No existe el post');
}
//We update the post to put the user that they send us and indicate that they have a file
$sql = "UPDATE mdl_forum_posts SET userid= ?, attachment= 1 WHERE id = ?";
$DB->execute($sql, array($userid, $postid));
$user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
$file_record = new stdClass;
$file_record->component = 'mod_forum';
$file_record->contextid = $context->id;
$file_record->userid = $userid;
$file_record->filearea = 'attachment';
$file_record->filename = $filename;
$file_record->filepath = '/';
$file_record->itemid = $postid;
$file_record->license = $CFG->sitedefaultlicense;
$file_record->author = fullname($user);
$file_record->source = $filename;
//Check if the file already exist
$existingfile = $fs->file_exists($file_record->contextid, $file_record->component, $file_record->filearea,
$file_record->itemid, $file_record->filepath, $file_record->filename);
if ($existingfile) {
throw new file_exception('filenameexist');
} else {
$stored_file = $fs->create_file_from_pathname($file_record, $filepath);
}
} else {
throw new moodle_exception('couldnotadd', 'forum');
}
}
}else{
throw new moodle_exception('nofile');
}
$result = array();
$result['discussionid'] = $discussionid;
$result['warnings'] = $warnings;
return $result;
}
/**
* Returns description of method result value
* #return external_multiple_structure
*/
public static function upload_tfg_returns() {
return new external_single_structure(
array(
'discussionid' => new external_value(PARAM_INT, 'New Discussion ID'),
'warnings' => new external_warnings()
)
);
}
}
And an example to call this WS maybe this:
$target_url = "http://localhost/pruebaMoodle/webservice/rest/server.php";
//$target_url = "http://localhost/upload.php";
$username = "raula"; //User uploading the file (must belong to the course)
$community_key = "c15c033a43976gPT"; //custom identifier of course
$folder_name = "Course 2016"; //Name of the forum to which the file will be uploaded
$fname = 'Prueba.txt'; //Name of the file or path where it is located but is in the same directory as this file
$token = "28b054f102a75a0eab2a0053fd930d62"; //token created for ws
$file_name_with_full_path = realpath($fname);
$cfile = new CURLFile($file_name_with_full_path);
$post = array (
'username' => $username,
'community_key' => $community_key,
'folder_name' => $folder_name,
'wstoken' => $token,
'wsfunction' => 'upload_tfg_tfm',
'moodlewsrestformat' => 'json',
'upload_file' => $cfile
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
curl_setopt($ch, CURLOPT_HTTPHEADER,array('User-Agent: Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12.388 Version/12.15','Referer: http://localhost','Content-Type: multipart/form-data'));
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
$result = curl_exec ($ch);
if ($result === FALSE) {
echo "Error sending " . $fname . " " . curl_error($ch) . "\n";
curl_close ($ch);
}else{
curl_close ($ch);
echo "<br><br>Result: " . $result. "<br>";
}
I hope this can serve you

Curl not writing cookie and http code 404, why?

I want to curl cookies
cookie file is created but empty, why?
And agent_http_code value: 404, why?
Thanks.
$url ="https://example.com";
$xmlfile = '/home/*******/public_html/2.xml';
$cookie_file = '/home/******/public_html/cookie.txt';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, array('action-xmlagentxmlfile'=>'#' . $xmlfile));
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
if (file_exists($cookie_file) && filesize($cookie_file) > 0) {
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
}

Graph API Explorer: delete scores

I'm trying to delete all "scores" from the "Graph API Explorer". I selected my application (at the top right), DELETE and wrote https://graph.facebook.com/APP_ID_OMITTED/scores (as request) but I get the error:
{
"error": {
"message": "(#15) This method must be called with an app access_token.",
"type": "OAuthException",
"code": 15
}
}
Where did I go wrong?
It's working now, here's the working code:
// Delete scores for all users
function get_app_access_token($app_id, $app_secret) {
$token_url = 'https://graph.facebook.com/oauth/access_token?'
. 'client_id=' . $app_id
. '&client_secret=' . $app_secret
. '&grant_type=client_credentials';
$token_response = file_get_contents($token_url);
$params = null;
parse_str($token_response, $params);
return $params['access_token'];
}
$app_id = 'OMITTED';
$app_secret = 'OMITTED';
$access_token = get_app_access_token($app_id, $app_secret);
$request_body = '';
$ch = curl_init('https://graph.facebook.com/'.$app_id.'/scores?access_token='.$access_token);
//curl_setopt($ch, CURLOPT_POSTFIELDS, $request_body);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
$response = curl_exec($ch);
var_dump($response);
Like the error message says, make sure you're using the Application Access Token
If you just use the Graph API explorer, you probably have a user access token for your account