drupal using node.save with XMLRPC call to another site. "Access Denied" message - drupal

I have a piece of code on 1 drupal site to create a node another drupal site in a multi-site setup.
It looks like I'm getting the sessionid and logging in just fine, but when trying to create a "page" node, I get "Access denied". Under Services -> Settings I have "Key Authentication", "Use keys" is unchecked, and "Use sessid" is checked. I agev permissions for the logged in user: "create page content", "administer services", etc...
Below is my code:
<p>Test Page 1</p>
<? $url = 'http://drupal2.dev/xmlrpc.php'; ?>
<?
$conn = xmlrpc($url, 'system.connect');
print_r($conn);
?>
<p>--</p>
<?
$login = xmlrpc($url, 'user.login', $conn['sessid'], 'superuser_name', 'superuser_password');
print_r($login);
?>
<p>--</p>
<?
$data=array('type'=>'page', 'title'=>'Test', 'body'=>'test');
$data_s=serialize($data);
$result = xmlrpc($url, 'node.save', $login['sessid'], $data_s);
echo $result;
//echo $data_s;
?>
<?
if($error = xmlrpc_error()){
if($error->code > 0){
$error->message = t('Outgoing HTTP request failed because the socket could not be opened.');
}
drupal_set_message(t('Operation failed because the remote site gave an error: %message (#code).',
array(
'%message' => $error->message,
'#code' => $error->code
)
)
);
}
?>
The ouput of this script is:
Array ( [sessid] => 9eebdde9bf0bfd9610cc2f03af131a9c [user] => Array ( [uid] => 0 [hostname] => ::1 [roles] => Array ( [1] => anonymous user ) [session] => [cache] => 0 ) )
--
Array ( [sessid] => c0ca4c599e41e97e7a7ceb43ee43249e [user] => Array ( [uid] => 1 [name] => eric [pass] => 13583b155536098b98df41bb69fcc53 [mail] => email#gmail.com [mode] => 0 [sort] => 0 [threshold] => 0 [theme] => [signature] => [signature_format] => 0 [created] => 1271813934 [access] => 1275867734 [login] => 1275868794 [status] => 1 [timezone] => [language] => [picture] => [init] => email#gmail.com [data] => a:0:{} [roles] => Array ( [2] => authenticated user ) ) )
--
Access denied

I discovered recently that PHP session ids are more complex than I had thought.
For them to work, your XMLRPC transport needs to fully support cookies, which are used for Drupal's authentication.
Without cookies, each request is treated as a new anonymous request and is given a new session ID. So the fact that you've logged in means nothing to the next xmlrpc call you make.
I'm doing some work in python, and made a custom transport object to support cookies, and now it all works for me. I found out how to do this in python here:
http://osdir.com/ml/python.cherrypy/2005-12/msg00142.html
(edit-add) I might also add that the services module is pretty bad with its error reporting. For example, if you send an argument as a string when it's expecting an array (with the string in the array) you can often get access denied errors which don't really reflect the fact that there is a parameter error.
Check that the service is working as you expect by testing it out under Admin > Site Building > Services > Browse and click the service you want to use.

site 1 code:
function exmple2_cron() {
homes_sync_get_node_list();
}
function homes_sync_get_node_list() {
$methods = xmlrpc('http://example.com/map/xmlrpc.php', array('system.listMethods' => array()));
$node_ids = xmlrpc('http://example.com/map/xmlrpc.php', array('node.getAllHomes'=>array()));
if (xmlrpc_error()) {
$error = xmlrpc_error();
watchdog('homes_sync', 'Error getting node list from parent server. Error: #error.', array('#error' => $error);
}
else {
foreach ($node_ids as $nid) {
$nodes[] = $nid;
}
variable_set('parent_home_nodes', $nodes);
watchdog('homes_sync', 'Successfully retrieved node list from parent server.', array(), WATCHDOG_NOTICE);
}
homes_sync_perform_update();
}
function homes_sync_perform_update() {
$node_ids = variable_get('parent_home_nodes', 0);
foreach ($node_ids as $nid) {
$data = xmlrpc('http://example.com/map/xmlrpc.php', array('node.get' => array($nid)));print_r($data);exit;
$result = db_fetch_array(db_query('SELECT n.nid, n.title, n.type FROM {node} n WHERE n.title = "%s" AND n.type = "%s"', $data['title'], 'page'));
if (xmlrpc_error()) {
$error = xmlrpc_error();
watchdog('homes_sync', 'Could not perform XMLRPC request. Error: #error.', array('#error' => $error), WATCHDOG_CRITICAL);
} else {
if (is_array($data)) {
$node = "";
if ($result && $result['nid']) {
$node->nid = $result['nid'];
}
$node->type = $data['type'];
$node->uid = 1;
$node->status = $data['status'];
$node->created = $data['created'];
$node->changed = $data['changed'];
$node->comment = $data['comment'];
$node->promote = $data['promote'];
$node->moderate = $data['moderate'];
$node->sticky = $data['sticky'];
$node->tnid = $data['tnid'];
$node->translate = $data['translate'];
$node->title = $data['title'];
$node->body = $data['body'];
$node->teaser = $data['teaser'];
$node->format = $data['format'];
$node->name = $data['name'];
$node->data = $data['data'];
$node->path = $data['path'];
node_save($node);
unset($node);
}
}
}
}
remote site code:
function example_xmlrpc() {
$methods = array();
$methods[] = array(
'node.getAllHomes',
'homes_service_node_get_all_homes',
array('int'),
);
return $methods;
}
function homes_service_node_get_all_homes() {
$query = db_query('SELECT n.* FROM {node} n');
foreach ($query as $record){
$nid[] = $record;
}
return $nid;
}

Related

Dynamically pull values from nested form using Gravity Forms & Gravity Wiz Nested Forms

So I've been going through a restructure build of an entire site, and part of that involved switching from Formidable Forms to Gravity Forms. We did this because we wanted to use the Nested Form feature, so that we could automate multiple attendees without having to create a new form for each.
Here's the problem - on our old site that did have a separate form per attendee via Formidable, we had a code using the Canvas API to send name + email info to Canvas and automatically register users for the online courses this company offers. In trying to convert sections of this code to work with my nested forms, I'm running into a snag:
The main issue is that the value is being spit out as all of the information from the nested form entry, not by name/ email/ etc.
The info is being spit out twice, perhaps because of the way the forms are structured? There are a couple calculations happening in the forms/ nested forms so I'm chalking it up to that.
[1] => WC_Meta_Data Object
(
[current_data:protected] => Array
(
[id] => 212
[key] => Attendee Registration
[value] =>
Name
Test Name
Email Address
courses#email.com
Cell Phone
(333) 333-3333
Would you like to receive text message reminders for this registration?
No
Post-class notification is required for the following states, please identify if you will be using this class to fulfill any state license requirements:
N/A
You'll receive a hard copy and digital certificate upon course completion. Additional options are available here:
All live classes include a hard copy manual and regulations. To join our effort to save paper, please also add any of the following options to take your books home:
)
[data:protected] => Array
(
[id] => 212
[key] => Attendee Registration
[value] =>
Name
Test Name
Email Address
courses#email.com
Cell Phone
(333) 333-3333
Would you like to receive text message reminders for this registration?
No
Post-class notification is required for the following states, please identify if you will be using this class to fulfill any state license requirements:
N/A
You'll receive a hard copy and digital certificate upon course completion. Additional options are available here:
All live classes include a hard copy manual and regulations. To join our effort to save paper, please also add any of the following options to take your books home:
)
)
Also: I was playing around with grabbing the ID of the main entry via [_gravity_form_linked_entry_id], and grabbing the nested info from that via [_gravity_form_lead].
The best I was able to get from that was this... so yeah kind of lost on how to progress here if anyone has any pointers! Thanks so much!
[data:protected] => Array
(
[id] => 211
[key] => _gravity_forms_history
[value] => Array
(
[_gravity_form_cart_item_key] => 72201a9586fb30895b8fb5cac2a796b9
[_gravity_form_linked_entry_id] => 125
[_gravity_form_lead] => Array
(
[form_id] => 1
[source_url] => https://chcv2.flywheelstaging.com/product/air-monitoring-specialist-live/
[ip] => 75.151.95.41
[42.1] => Course Price
[42.2] => $580.00
[42.3] => 1
[21] => 122
[40.1] => Add-On Fees
[40.2] => $0.00
[40.3] => 1
)
[_gravity_form_data] => Array
(
[id] => 1
[bulk_id] => 0
[display_title] =>
[display_description] =>
[disable_woocommerce_price] => no
[price_before] =>
[price_after] =>
[disable_calculations] => no
[disable_label_subtotal] => yes
[disable_label_options] => yes
[disable_label_total] => no
[disable_anchor] => no
[label_subtotal] => Course Fee
[label_options] => Additional Attendees + Selected Options
[label_total] => Attendee Registration + Add-Ons:
[use_ajax] => no
[enable_cart_edit] => no
[enable_cart_edit_remove] => no
[keep_cart_entries] => no
[send_notifications] => no
[enable_cart_quantity_management] => stock
[cart_quantity_field] =>
[update_payment_details] => yes
[display_totals_location] => after
[structured_data_override] => no
[structured_data_low_price] =>
[structured_data_high_price] =>
[structured_data_override_type] => overwrite
)
)
)
Update: Here's how I've incorporated the code from Rochelle's comment below, where I'm getting an error
add_action( 'woocommerce_thankyou', 'canvas_enroll', 20, 2 );
function canvas_enroll($orders) {
$query = new WC_Order_Query( array(
'orderby' => 'date',
'order' => 'DESC',
'return' => 'ids',
) );
$orders = $query->get_orders();
foreach($orders as $order){
foreach ($order->get_items() as $item_id => $item_data) {
if(isset($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]["form_id"]) && !empty($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]["form_id"])){
$linked_entry=$item_data->get_meta( '_gravity_forms_history')["_gravity_form_linked_entry_id"];
$entry_id = $linked_entry;
$entry = GFAPI::get_entry( $entry_id );//id of Parent Gravity Form
if(isset($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2']) && !empty($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2'])){
$linked_nested_value=$item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2'];
$nested_value_array = preg_split ("/\,/", $linked_nested_value); //array of child entries
$child_entry_amt = substr_count($linked_nested_value, ",") + 1;
if ($child_entry_amt > 0){
for ($n = 0; $n < $child_entry_amt; $n++) {
$entry_id_nest[$n]=$nested_value_array[$n];
$entry_nest[$n] = GFAPI::get_entry( $entry_id_nest[$n] ); //nested form entry
$name[$n] = $entry_nest[$n]['12.3'].''.$entry_nest[$n]['12.6'];//replace 1.3 and 1.6 with nested field id of name
$email[$n] = $entry_nest[$n]['11']; //2 is the GF nested field id of email
}
}
}
}
}
}
}
Finally got this figured out! Something that was super helpful was to echo the item meta data ($value, in my case) for that to display all the ids and such, that's how I was able to figure out that I needed 21 in that ID for the child entries.
I'm not really sure why I had to switch to wc_get_order instead of wc_order_query, but it solved the errors I was getting.
function canvas_enroll($order_id) {
$order = wc_get_order( $order_id);
$order_id = array(
'orderby' => 'date',
'order' => 'DESC',
'return' => 'ids',
);
if(!empty($order) && isset($order)){
// Loop through order line items
foreach( $order->get_items() as $key => $value ){
// get order item data (in an unprotected array)
if(isset($value->get_meta( '_gravity_forms_history')["_gravity_form_lead"]["form_id"]) && !empty($value->get_meta( '_gravity_forms_history')["_gravity_form_lead"]["form_id"])){
$linked_entry=$value->get_meta( '_gravity_forms_history')["_gravity_form_linked_entry_id"];
$entry_id = $linked_entry;
$entry = GFAPI::get_entry( $entry_id );//id of Parent Gravity Form
if(isset($value->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['21']) && !empty($value->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['21'])) { //21 was the id for my child form
$linked_nested_value = $value->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['21'];
$nested_value_array = preg_split ("/\,/", $linked_nested_value); //array of child entries
$child_entry_amt = substr_count($linked_nested_value, ",") + 1;
if ($child_entry_amt > 0){
for ($n = 0; $n < $child_entry_amt; $n++) {
$entry_id_nest[$n]=$nested_value_array[$n];
$entry_nest[$n] = GFAPI::get_entry( $entry_id_nest[$n] ); //nested form entry
$firstname[$n] = $entry_nest[$n]['12.3'];//replace 12.3 with nested field id of first name
$lastname[$n] = $entry_nest[$n]['12.6'];//replace 12.6 with nested field id of last name
$email[$n] = $entry_nest[$n]['11']; //replace 11 with nested field id of email
}
}
}
}
}
}
}
I'm just going to paste the code I used for another project that I needed to pull the same type of data in case it puts you on the right track. You'd have to replace the numbers with the ids from your forms:
$query = new WC_Order_Query( array(
'orderby' => 'date',
'order' => 'DESC',
'return' => 'ids',
) );
$orders = $query->get_orders();
foreach($orders as $order){
foreach ($order->get_items() as $item_id => $item_data) {
if(isset($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]["form_id"]) && !empty($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]["form_id"])){
$linked_entry=$item_data->get_meta( '_gravity_forms_history')["_gravity_form_linked_entry_id"];
$entry_id = $linked_entry;
$entry = GFAPI::get_entry( $entry_id );//id of Parent Gravity Form
if(isset($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2']) && !empty($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2'])){
$linked_nested_value=$item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2'];
$nested_value_array = preg_split ("/\,/", $linked_nested_value); //array of child entries
$child_entry_amt = substr_count($linked_nested_value, ",") + 1;
if ($child_entry_amt > 0){
for ($n = 0; $n < $child_entry_amt; $n++) {
$entry_id_nest[$n]=$nested_value_array[$n];
$entry_nest[$n] = GFAPI::get_entry( $entry_id_nest[$n] ); //nested form entry
$name[$n] = $entry_nest[$n]['1.3'].''.$entry_nest[$n]['1.6'];//replace 1.3 and 1.6 with nested field id of name
$email[$n] = $entry_nest[$n]['2']; //2 is the GF nested field id of email
}
}
}
}
}
}
Ok. Try this first to see if it changes anything:
$query = new WC_Order_Query( array(
'orderby' => 'date',
'order' => 'DESC',
'return' => 'ids',
) );
$orders = $query->get_orders();
foreach($orders as $order){
if(!empty($order) && isset($order)){
foreach ($order->get_items() as $item_id => $item_data) {
if(isset($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]["form_id"]) && !empty($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]["form_id"])){
$linked_entry=$item_data->get_meta( '_gravity_forms_history')["_gravity_form_linked_entry_id"];
$entry_id = $linked_entry;
$entry = GFAPI::get_entry( $entry_id );//id of Parent Gravity Form
if(isset($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2']) && !empty($item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2'])){
$linked_nested_value=$item_data->get_meta( '_gravity_forms_history')["_gravity_form_lead"]['2'];
$nested_value_array = preg_split ("/\,/", $linked_nested_value); //array of child entries
$child_entry_amt = substr_count($linked_nested_value, ",") + 1;
if ($child_entry_amt > 0){
for ($n = 0; $n < $child_entry_amt; $n++) {
$entry_id_nest[$n]=$nested_value_array[$n];
$entry_nest[$n] = GFAPI::get_entry( $entry_id_nest[$n] ); //nested form entry
$name[$n] = $entry_nest[$n]['1.3'].''.$entry_nest[$n]['1.6'];//replace 1.3 and 1.6 with nested field id of name
$email[$n] = $entry_nest[$n]['2']; //2 is the GF nested field id of email
}
}
}
}
}
}
}

Connection codeigniter and wordpress

The situation is as: wordpress installation in root and ci installation in /subdomain1 of subdomain1.domain.com.
I want to perform the following; users from my wordpress site can login with the same credentials in the codeigniter app. I tried methods explained here and in other tutorials but one thing keeps happening. When I add require_once('../wp-load.php'); in the index.php file from ci it and adjusted the load.php file and MY_url_helper.php file it keeps redirecting to: subdomain1.domain.com/index.php/login/wp-admin/install.php I tried to shut off rewriting but it doesn't seem to fix this.
Anyone have a solution? I would really appreciate it!
There are two methods:
1. Load the Wordpress Database in your Codeigniter
To do so add to your "application/config/database.php":
$db['wordpress'] = array(
'dsn' => '',
'hostname' => 'localhost',
'username' => '#',
'password' => '#',
'database' => '#',
'dbdriver' => 'mysqli',
'dbprefix' => '',
'pconnect' => FALSE,
'db_debug' => (ENVIRONMENT !== 'production'),
'cache_on' => FALSE,
'cachedir' => '',
'char_set' => 'utf8',
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'encrypt' => FALSE,
'compress' => FALSE,
'stricton' => FALSE,
'failover' => array(),
'save_queries' => TRUE
);
Don't forget to replace '#' with your database login information.
After that you can load the database where ever needed with
$this->load->database('wordpress');
Source: https://www.codeigniter.com/user_guide/database/connecting.html
2. Use the Wordpress wp-load.php
Where ever needed to see if the user is logged in use the following code (PS: at the end there is also a check included how you could check if a user purchased a product via EasyDigitalDownloads in your Wordpress installation - if needed):
<?php
define( 'WP_USE_THEMES', false ); // Do not use the theme files
define( 'COOKIE_DOMAIN', false ); // Do not append verify the domain to the cookie
define( 'DISABLE_WP_CRON', true ); // We don't want extra things running...
//$_SERVER['HTTP_HOST'] = ""; // For multi-site ONLY. Provide the
// URL/blog you want to auth to.
// Path (absolute or relative) to where your WP core is running
require("/var/www/yourdomain.com/htdocs/wp-load.php");
if ( is_user_logged_in() ) {
$user = wp_get_current_user();
} else {
$creds = array();
// If you're not logged in, you should display a form or something
// Use the submited information to populate the user_login & user_password
$creds['user_login'] = "";
$creds['user_password'] = "";
$creds['remember'] = true;
$user = wp_signon( $creds, false );
if ( is_wp_error( $user ) ) {
echo $user->get_error_message();
} else {
wp_set_auth_cookie( $user->ID, true );
}
}
if ( !is_wp_error( $user ) ) {
// Success! We're logged in! Now let's test against EDD's purchase of my "service."
if ( edd_has_user_purchased( $user->ID, '294', NULL ) ) {
echo "Purchased the Services and is active.";
} else {
echo "Not Purchased";
}
}
Source: http://dovy.io/wordpress/authenticating-outside-of-wordpress-on-diff-domain/

PHP-SDK publish link not available for public

When publishing a new link, using php sdk, the link is only available for logged user, it's not publish as public.
$facebook = new Facebook(array(
'appId' => $appId,
'secret' => $secret,
'cookie' => true
));
$user = $facebook->getUser(); // Get the UID of the connected user, or 0 if the Facebook user is not connected.
if($user == 0) {
setcookie('cod_eventos', $_POST['cod_eventos']);
$login_url = $facebook->getLoginUrl($params = array('scope' => "publish_stream"));
setcookie('userlogin', 1);
echo ("<script>window.open('".$login_url."')</script>");
} else {
$page_id = $page_id;
try {
$access_token = $facebook->getAccessToken();
$attachment2 = array(
'access_token' => $access_token
);
$page = $facebook->api('/me/accounts', 'get', $attachment2);
} catch (FacebookApiException $e) {
echo 'Unable to get page access token';
}
$privacy = array(
'value' => 'EVERYONE',
);
$attachment = array(
'access_token' => $page['data'][0]['access_token'],
'name' => 'Test',
'link' => 'http://www.facebook.com/',
'description' =>'Facebook',
'privacy' => json_encode($privacy),
);
try {
$facebook->api('/' . $page_id . '/feed', 'POST', $attachment);
echo '<div class="gestor_ficheiros_tipo">Event publish Facebook</div>';
}
catch (FacebookApiException $e)
{
echo '<div class="gestor_ficheiros_tipo">'.$e->getMessage().'</div>';
}
After running this the content is publish, but not view-able by un-registered facebook users
Apparently, despite what the API documentation says, the privacy setting is 'privacy_type', not 'privacy'. I found that out here on SO I think, but closed the tab so I can't immediately share the link.
Check the settings on your app as well - I think it's the 'Visibility of app and posts' setting defaults to 'Friends' instead of 'Public'. Maybe that'll do it?
I found out what was the problem, I was using facebook app in sandbox mode... :(. Once I've changed it started working perfectly

PDOException on Duplicate filename in Drupal 7

Using the following code:
foreach ($form_state['values']['uploads'] as $key => $value) {
if (strlen($value)) {
$file = file_save_upload($key, array(
'file_validate_is_image' => array(), // Validates file is really an image.
'file_validate_extensions' => array('png gif jpg jpeg'), // Validate extensions.
));
// If the file passed validation:
if ($file) {
// Move the file, into the Drupal file system
if ($file = file_move($file, 'public://')) {
// Save the file for use in the submit handler.
$form_state['values']['uploaded_photos'][] = $file;
$x++;
} else {
form_set_error($key, t('Failed to write the uploaded file the site\'s file folder.'));
}
}
}
}
I am trying to save images attached to a form into a cached object with CTools. All of that was working fine, until I tried uploading the same file again, and I got a white screen that said "Error - The website encountered an error." (ripped from watchdog):
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'public://ad-10.jpg'; for key 2: UPDATE {file_managed} SET uid=:db_update_placeholder_0, filename=:db_update_placeholder_1, uri=:db_update_placeholder_2, filemime=:db_update_placeholder_3, filesize=:db_update_placeholder_4, status=:db_update_placeholder_5, timestamp=:db_update_placeholder_6
WHERE (fid = :db_condition_placeholder_0) ; Array
(
[:db_update_placeholder_0] => 0
[:db_update_placeholder_1] => ad-10.jpg
[:db_update_placeholder_2] => public://ad-10.jpg
[:db_update_placeholder_3] => image/jpeg
[:db_update_placeholder_4] => 4912
[:db_update_placeholder_5] => 0
[:db_update_placeholder_6] => 1326221376
[:db_condition_placeholder_0] => 834
)
";s:9:"%function";s:21:"drupal_write_record()";
Since I am not setting the $replace argument, shouldn't it default to FILE_EXISTS_RENAME and therefor not throw this error? How can I resolve this?
Try this module. It fixes the issue of concurrent file object being written to db. https://drupal.org/project/upload_qc
I can't comment as to why that doesn't work (it looks like it certainly should) but I can offer a simpler solution.
Drupal actually has a form widget built-in to handle file uploads, the managed_file type. It handles all of the file uploading/validating for you, you just need to mark the files as permanent in your form's submit handler.
So in your form function:
$form['files'] = array('#tree' => TRUE);
for ($i = 0; $i < $num_file_fields; $i++) {
$form['files']["file_$i"] = array(
'#type' => 'managed_file',
'#title' => 'Select a file',
'#upload_location' => 'public://',
'#upload_validators' => array(
'file_validate_is_image' => array(),
'file_validate_extensions' => array('png gif jpg jpeg')
)
);
}
And then in your submit handler:
$count = count($form_state['values']['files']);
for ($i = 0; $i < $count; $i++) {
$file = file_load($form_state['values']['files']["file_$i"]);
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
}
Hope that helps
I had the same issue because of strange unused temporary files.
You can check if you have unused files using:
$result = db_select('file_managed', 'f')
->fields('f', array('fid'))
->condition('f.uri', db_like('temporary://') . '%', 'LIKE')
->execute()->fetchCol();
foreach ($result as $fid) {
if ($file = file_load($fid)) {
if (!file_usage_list($file)) {
dpm($file->filename);
}
}
}
If you fail to upload file with the same name that you see, you can remove them(But double check and backup first):
/**
* Clean unused temporary files.
*/
function MYMODULE_update_7007() {
$files = db_select('file_managed', 'f')
->fields('f', array('fid'))
->condition('f.uri', db_like('temporary://') . '%', 'LIKE')
->execute()->fetchCol();
foreach ($files as $fid) {
if ($file = file_load($fid)) {
$references = file_usage_list($file);
if (empty($references)) {
if (!file_delete($file)) {
watchdog('file system', 'Could not delete temporary file "%path" during garbage collection', array('%path' => $file->uri), WATCHDOG_ERROR);
}
}
else {
watchdog('file system', 'Did not delete temporary file "%path" during garbage collection, because it is in use by the following modules: %modules.', array('%path' => $file->uri, '%modules' => implode(', ', array_keys($references))), WATCHDOG_INFO);
}
}
}
}

Uploading and saving a file programmatically to Drupal nodes

I am trying to create a node based on a custom form submission. Everything works great except for the images that get uploaded.
I can capture them fine and set them in the form object cache. When I pass the data into the function to create the node, I get this error:
"The specified file could not be copied, because no file by that name exists. Please check that you supplied the correct filename."
I also receive the error multiple times, despite only submitting one or two images at a time.
Here is the code I am using. $uploads is passed in and is an array of file objects returned from file_save_upload() in a previous step:
if (isset($uploads)) {
foreach ($uploads as $upload) {
if (isset($upload)) {
$file = new stdClass;
$file->uid = 1;
$file->uri = $upload->filepath;
$file->filemime = file_get_mimetype($upload->uri);
$file->status = 1;
$file = file_copy($file, 'public://images');
$node->field_image[$node->language][] = (array) $file;
}
}
}
node_save($node);
I also tried this:
if (isset($uploads)) {
foreach ($uploads as $upload) {
$upload->status = 1;
file_save($upload);
$node->field_image[$node->language][] = (array) $upload;
}
}
}
node_save($node);
The second causes a duplicate key error in MySQL on the URI field. Both of these examples I saw in tutorials, but neither are working?
For Drupal 7, I played around with this quite a bit and found the best way (and only way that I've got working) was to use Entity metadata wrappers
I used a managed file form element like so:
// Add file upload widget
// Use the #managed_file FAPI element to upload a document.
$form['response_document'] = array(
'#title' => t('Attach a response document'),
'#type' => 'managed_file',
'#description' => t('Please use the Choose file button to attach a response document<br><strong>Allowed extensions: pdf doc docx</strong>.'),
'#upload_validators' => array('file_validate_extensions' => array('pdf doc docx')),
'#upload_location' => 'public://my_destination/response_documents/',
);
I also pass along the $node object in my form as a value
$form['node'] = array('#type' => 'value', '#value' => $node);
Then in my submission handler I simply do the following:
$values = $form_state['values'];
$node = $values['node'];
// Load the file and save it as a permanent file, attach it to our $node.
$file = file_load($values['response_document']);
if ($file) {
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
// Attach the file to the node.
$wrapper = entity_metadata_wrapper('node', $node);
$wrapper->field_response_files[] = array(
'fid' => $file->fid,
'display' => TRUE,
'description' => $file->filename,
);
node_save($node);
}
i used your code to upload a file in the file field to a content("document" in my case) and it's worked. Just had to add a value for field_document_file 'display' in the code.
here is the exact script i used:
<?php
// Bootstrap Drupal
define('DRUPAL_ROOT', getcwd());
require_once './includes/bootstrap.inc';
require_once './includes/file.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
// Construct the new node object.
$path = 'Documents/document1.doc';
$filetitle = 'test';
$filename = 'document1.doc';
$node = new StdClass();
$file_temp = file_get_contents($path);
//Saves a file to the specified destination and creates a database entry.
$file_temp = file_save_data($file_temp, 'public://' . $filename, FILE_EXISTS_RENAME);
$node->title = $filetitle;
$node->body[LANGUAGE_NONE][0]['value'] = "The body of test upload document.\n\nAdditional Information";
$node->uid = 1;
$node->status = 1;
$node->type = 'document';
$node->language = 'und';
$node->field_document_files = array(
'und' => array(
0 => array(
'fid' => $file_temp->fid,
'filename' => $file_temp->filename,
'filemime' => $file_temp->filemime,
'uid' => 1,
'uri' => $file_temp->uri,
'status' => 1,
'display' => 1
)
)
);
$node->field_taxonomy = array('und' => array(
0 => array(
'tid' => 76
)
));
node_save($node);
?>
Kevin, that's what I found in the Drupal doc's under http://drupal.org/node/201594 below in the comments. But I am not sure at all. I try the same, so please let me know what you found out.
$path = './sites/default/files/test.jpg';
$filetitle = 'test';
$filename = 'test.jpg';
$node = new StdClass();
$file_temp = file_get_contents($path);
$file_temp = file_save_data($file_temp, 'public://' . $filename, FILE_EXISTS_RENAME);
$node->title = $filetitle;
$node->uid = 1;
$node->status = 1;
$node->type = '[content_type]';
$node->language = 'und';
$node->field_images = array(
'und' => array(
0 => array(
'fid' => $file_temp->fid,
'filename' => $file_temp->filename,
'filemime' => $file_temp->filemime,
'uid' => 1,
'uri' => $file_temp->uri,
'status' => 1
)
)
);
$node->field_taxonomy = array('und' => array(
0 => array(
'tid' => 76
)
));
node_save($node);

Resources