23.05 - Uncaught Error: Attempt to assign property "domain_records"
-
Hummm.
I stand corrected.
You - @chrisjx - are the first one ... not looking in https://redmine.pfsense.org/projects/pfsense-plus/issues?set_filter=1&tracker_id=1
And me the second of course, as I didn't check the "its already known" list neither.
Strange that an issue like that - 20 days old - wasn't get caught.
The solution must be simple ..... if I could get my hands on a digitalocean account. -
@Gertjan @stephenw10 - Thanks. Next time, I will try to remember to look up the issue in redmine.
This is what the code shows:
case 'digitalocean': case 'digitalocean-v6': // Get record ID $server = 'https://api.digitalocean.com/v2/domains/'; $isv6 = ($this->_dnsService === 'digitalocean-v6'); $url = $server . $this->_dnsDomain . '/records'; curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$this->_dnsPass}")); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FORBID_REUSE, true); $output = json_decode(curl_exec($ch)); if (!is_array($output->domain_records)) { $output->domain_records = array(); }
The offending line, 1425, is:
$output->domain_records = array();
At the top of the code it shows this:
* DigitalOcean - Not Yet Tested
I'm not familiar enough with PHP to understand the problem. I'd be glad to test if you have a suggeted fix.
-
@chrisjx said in 23.05 - Uncaught Error: Attempt to assign property "domain_records":
$output = json_decode(curl_exec($ch));
which means $output is an object, not an array.
Try this :
$output = json_decode(curl_exec($ch), true);
-
Almost all the php errors we see are because a variable has not been initialised. php7 allowed a lot more flexibility with those but php8 throws errors.
-
I updated the line to:
$output = json_decode(curl_exec($ch), true);
And I have not seen the problem since.
Thank you.
-
You want to update the bug? Or file a pull-request?
-
I placed a link back to here.
-
Sad to say, I was travelling for a few days and now see the fix did not work. This is the new error response being thrown:
PHP ERROR: Type: 1, File: /etc/inc/dyndns.class, Line: 1429, Message: Uncaught Error: Attempt to assign property "domain_records" on array in /etc/inc/dyndns.class:1429 Stack trace: #0 /etc/inc/dyndns.class(479): updatedns->_update() #1 /etc/inc/services.inc(2348): updatedns->__construct('digitalocean', 'xxx...', 'xxx...', 'xxx...', 'ZG9wX3YxXzZmZjQ...', false, false, '', 'fail_me', NULL, NULL, NULL, '', '', '', '300', '', 'fail_me', '', '3', true, false, false, NULL) #2 /etc/inc/services.inc(2423): services_dyndns_configure_client(Array) #3 /etc/rc.dyndns.update(40): services_dyndns_configure() #4 {main}
This is what the current code around line 1429 looks like:
case 'digitalocean': case 'digitalocean-v6': // Get record ID $server = 'https://api.digitalocean.com/v2/domains/'; $isv6 = ($this->_dnsService === 'digitalocean-v6'); $url = $server . $this->_dnsDomain . '/records'; curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$this->_dnsPass}")); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FORBID_REUSE, true); // ChrisJ, updated this line, 2023-06-05 // $output = json_decode(curl_exec($ch)); $output = json_decode(curl_exec($ch), true); if (!is_array($output->domain_records)) { $output->domain_records = array(); // <-- line 1429 }
Apologies for a less than thorough testing.
Chris.
-
@chrisjx said in 23.05 - Uncaught Error: Attempt to assign property "domain_records":
/etc/inc/dyndns.class:1429
Line 1429 is a comment line
https://github.com/pfsense/pfsense/blob/5e92d678f642277642acb7f471cd430ed53aae16/src/etc/inc/dyndns.class#L1429 -
I guess he added 3 lines there.
-
Sorry,
Line 1429 is from the edited file on my system which includes a few lines to space out the location visually and which also includes a comment.
The error is being thrown is (originally line 1425):
$output->domain_records = array();
The definition of $output precedes this line and was the one I altered per the suggestion:
from:$output = json_decode(curl_exec($ch));
to this:
$output = json_decode(curl_exec($ch), true);
I assume that the value being returned from
$output->domain_records
is not an array, and so the logic is trying to convert it. I see that the optional 'true' value should have fixed that.
Again, I'm not much experienced in php. Can you suggest a process to debug and see what is being returned in the call to:
$output = json_decode(curl_exec($ch), true);
Thank you,
Chris. -
I added the following to the code (before the ) in attempt to see what was going on:
log_error(sprintf(gettext("DO API output: %s"), $output)); log_error(sprintf(gettext("DO output domain records: %s"), $output->domain_records));
This is the result found in the system.log file:
Jun 12 11:55:52 pfSense php-fpm[62289]: /rc.dyndns.update: DO API output: Array Jun 12 11:55:52 pfSense php-fpm[62289]: /rc.dyndns.update: DO output domain records:
It looks like the first is just returning the type, Array, and the second, $output->domain_records, has no value.
-
Line 1430 :
Before assigning
$_domain_records = $output->domain_records;
set $_domain_records as an array:
$_domain_records = array();
-
I made the changes, I think, per your suggestion. Sadly I see the same error:
The error, after reboot:
PHP ERROR: Type: 1, File: /etc/inc/dyndns.class, Line: 1434, Message: Uncaught Error: Attempt to assign property "domain_records" on array in /etc/inc/dyndns.class:1434 Stack trace: #0 /etc/inc/dyndns.class(479): updatedns->_update() #1 /etc/inc/services.inc(2348): updatedns->__construct('digitalocean', 'photobox-ex', 'xxx', 'cjefferies2', 'xxx...', false, false, '', 'fail_me', NULL, NULL, NULL, '', NULL, '', '300', '', 'fail_me', '', '3', false, false, false, NULL) #2 /etc/inc/services.inc(2423): services_dyndns_configure_client(Array) #3 /etc/rc.dyndns.update(40): services_dyndns_configure() #4 {main}
The current code section:
case 'digitalocean-v6': // Get record ID $server = 'https://api.digitalocean.com/v2/domains/'; $isv6 = ($this->_dnsService === 'digitalocean-v6'); $url = $server . $this->_dnsDomain . '/records'; curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$this->_dnsPass}")); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FORBID_REUSE, true); // ChrisJ, updated this line, 2023-06-05 // $output = json_decode(curl_exec($ch)); $output = json_decode(curl_exec($ch), true); // print("<pre>" . $output); // print($output->domain_records . "</pre>" ); log_error(sprintf(gettext("DO API output: %s"), $output)); log_error(sprintf(gettext("DO output domain records: %s"), $output->domain_records)); if (!is_array($output->domain_records)) { $output->domain_records = array(); // <=== line 1434 in my current version } // DO's API lists 20 NS records per page, so additional pages needs to be downloaded // xxxs://redmine.pfsense.org/issues/10952 $_domain_records = array(); // <=== added $_domain_records = $output->domain_records; // <=== added $_count = count($_domain_records); $_total = 0; if (property_exists($output, 'meta')) {...
Thanks.
-
BTW, in case I've got some odd version, here's the header of the file, /etc/inc/dyndns.class:
Had to modify the URLs to get this submitted. Woe the tedium... ;)
* dyndns.class * * part of pfSense (pfsense.org) * Copyright (c) 2004-2013 BSD Perimeter * Copyright (c) 2013-2016 Electric Sheep Fencing * Copyright (c) 2014-2023 Rubicon Communications, LLC (Netgate) * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * PHP.updateDNS (pfSense version) * * +====================================================+ * Services Supported: * - All-Inkl (all-inkl) * - Amazon Route 53 (aws.amazon) * - Azure DNS (azure.microsoft) * - City Network (citynetwork.se) * - Cloudflare (cloudflare) * - Cloudflare IPv6 (cloudflare) * - ClouDNS (cloudns.net) * - Custom DDNS (any URL) * - Custom DDNS IPv6 (any URL) * - deSEC (desec.io) * - DHS (dhs.org) * - DNS Made Easy (dnsmadeeasy) * - DNS-O-Matic (dnsomatic) * - DNSexit (dnsexit) * - DNSimple (dnsimple * - DreamHost DNS (dreamhost) * - DuiaDNS (duiadns) * - DuiaDNS IPv6 (duiadns) * - DY.fi (dy.fi) * - DynDns (dyndns) [dynamic, static, custom] * - DynS (dyns) * - Dynv6 (dynv6) * - EasyDNS (easydns) * - EasyDNS IPv6 (easydns) * - Eurodns (eurodns) * - FreeDNS API v1 (freedns.afraid.) * - FreeDNS API v2 (freedns.afraid.) * - FreeDNS IPv6 API v1 (freedns.afraid.) * - FreeDNS IPv6 API v2 (freedns.afraid.) * - Gandi LiveDNS (gandi.) * - GleSYS (glesys.) * - GoDaddy (godaddy.) * - Google Domains (domains.google.) * - GratisDNS (gratisdns.dk) * - HE.net (dns.he.) * - HE.net IPv6 (dns.he.) * - HE.net Tunnelbroker IP update (ipv4.tunnelbroker.) * - HN (hn.org) -- incomplete checking! * - Hover (hover.) * - Loopia (loopia.) * - Name. (name.) * - Name. IPv6 (name.) * - Namecheap (namecheap.) * - No-IP (no-ip.) * - OpenDNS (opendns.) * - SelfHost (selfhost. * - SPDYN (spdyn.) * - SPDYN IPv6 (spdyn.) * - StaticCling (staticcling.) * - Strato (strato.) * - ZoneEdit (zoneedit.) * +----------------------------------------------------+ * Requirements: * - PHP version 4.0.2 or higher with the CURL Library and the PCRE Library * +----------------------------------------------------+ * Public Functions * - updatedns() * * Private Functions * - _update() * - _checkStatus() * - _error() * - _detectChange() * - _debug() * - _checkIP() * +----------------------------------------------------+ * All-Inkl - Last Tested: 12 November 2016 * Amazon Route 53 - Last Tested: 04 February 2017 * Azure DNS - Last Tested: 08 March 2018 * City Network - Last Tested: 13 November 2013 * Cloudflare - Last Tested: 05 September 2016 * Cloudflare IPv6 - Last Tested: 17 July 2016 * ClouDNS - Last Tested: 22 August 2017 * deSEC - Last Tested: NEVER * deSEC IPv6 - Last Tested: NEVER * DHS - Last Tested: 12 July 2005 * DigitalOcean - Not Yet Tested * DNS Made Easy - Last Tested: 27 April 2015 * DNS-O-Matic - Last Tested: 9 September 2010 * DNSexit - Last Tested: 27 June 2022 * DNSimple - Last Tested: 09 February 2015 * DreamHost - Last Tested: 30 April 2017 * DreamHost IPv6 - Not Yet Tested * DuiaDNS - Last Tested: 25 November 2016 * DuiaDNS IPv6 - Last Tested: 25 November 2016 * DY.fi - Last Tested: 22 April 2021 * DynDNS Custom - Last Tested: NEVER * DynDNS Dynamic - Last Tested: 12 July 2005 * DynDNS Static - Last Tested: NEVER * Dyns - Last Tested: NEVER * EasyDNS - Last Tested: 20 July 2008 * Eurodns - Last Tested: 27 June 2013 * FreeDNS - Last Tested: 01 May 2016 * FreeDNS IPv6 - Last Tested: 01 May 2016 * FreeDNS IPv6 v2 - Last Tested: 01 June 2020 * FreeDNS v2 - Last Tested: 01 June 2020 * Gandi LiveDNS - Not Yet Tested * GleSYS - Last Tested: 3 February 2015 * GoDaddy - Last Tested: 22 November 2017 * GoDaddy IPv6 - Last Tested: 22 November 2017 * Google Domains - Last Tested: 27 April 2015 * GratisDNS - Last Tested: 15 August 2012 * HE.net - Last Tested: 7 July 2013 * HE.net IPv6 - Last Tested: 7 July 2013 * HE.net Tunnel - Last Tested: 28 June 2011 * HN.org - Last Tested: 12 July 2005 * Hover - Last Tested: 15 February 2017 * Loopia - Last Tested: 21 August 2019 * Name. - Last Tested: 5 Dec 2021 * Name. IPv6 - Last Tested: 5 Dec 2021 * Namecheap - Last Tested: 31 August 2010 * No-IP - Last Tested: 20 July 2008 * ODS - Last Tested: 02 August 2005 * OpenDNS - Last Tested: 4 August 2008 * OVH DynHOST - Last Tested: NEVER * SelfHost - Last Tested: 26 December 2011 * SPDYN - Last Tested: 02 July 2016 * SPDYN IPv6 - Last Tested: 02 July 2016 * StaticCling - Last Tested: 27 April 2006 * Strato - Last Tested: 29 May 2021 * ZoneEdit - Last Tested: NEVER * +====================================================+ * * @author E.Kristensen * @version 0.8 * @updated 13 October 05 at 21:02:42 GMT * * DNSexit/OpenDNS support and multiwan extension for pfSense by Ermal Luçi and Koen Zomers * Custom DNS support by Matt Corallo * */
Thanks.
-
Try changing it to
$output = json_decode(curl_exec($ch), false);
Passing
true
there forces the function to return an associative array, which it already appears to be doing. What the code at the point of the error expects is an object, not an array. -
The more I look at this, it seems like the real problem is the response it's getting back from DO is not JSON so that variable ends up
null
instead of an object.Some extra safety checks would prevent the PHP error but they would not make it work.
Someone with that service will need to test what the response actually is there and maybe come up with an alternate way of parsing it. It's possible the upstream API changed the response to another format (e.g. XML, not JSON), or maybe it's passing back an error because something in the request is wrong.
-
i'm pretty sure it's still json and it's probably an error
maybe @chrisjx can use postman / insomnia to check what the answer is
maybe, but i'm just putting random stuff here without an account on digitalocean to try
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , "Authorization: Bearer {$this->_dnsPass}"));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);https://docs.digitalocean.com/reference/api/api-reference/#operation/domains_list_records
https://docs.digitalocean.com/reference/api/api-reference/#operation/domains_update_record
-
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer <my-do-api-key>" "https://api.digitalocean.com/v2/domains/<my-root-domain>/records"
I can confirm that executing the CURL command (as described in the DO API page) returns a fully loaded json set with name, data (ip), etc. It had 10 entries that looked like this:
{ "id": 299240866, "type": "A", "name": "xxxxxx", "data": "xx.xx.xxx.xx", "priority": null, "port": null, "ttl": 300, "weight": null, "flags": null, "tag": null }
Will try to log the values being returned in the code and see what's different.
Apologies for delay... appreciate the effort of those persisting with ideas.
Thank you.
-
This below seems to be working; IOW, not throwing any errors:
Starting at what I think is line 1414. It's kind of messy but I was trying to figure out how to display the return values into the system log file. I'm jut no good at understanding how to stringify objects in PHP. In any case the five minute errors are no longer happening and I'm seeing messages like this every 5 minutes instead of errors:
rc.dyndns.update: phpDynDNS (music): No change in my IP address and/or 25 days has not passed. Not updating dynamic DNS entry.
Working...
case 'digitalocean': case 'digitalocean-v6': // Get record ID $server = 'https://api.digitalocean.com/v2/domains/'; $isv6 = ($this->_dnsService === 'digitalocean-v6'); $url = $server . $this->_dnsDomain . '/records'; curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$this->_dnsPass}")); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FORBID_REUSE, true); // original line where error was thrown // $output = json_decode(curl_exec($ch)); $response = curl_exec($ch); // log_error(sprintf(gettext("DO API response: %s"), var_export($response))); $output = json_decode($response); // log_error(sprintf(gettext("DO API output: %s"), var_export($output))); // log_error(sprintf(gettext("DO API output domain records: %s"), var_export($output->domain_records))); if (!is_array($output->domain_records)) { $output->domain_records = array(); }
Thanks,
Chris